Skip to content

Commit

Permalink
Merge pull request apache#1205, annotation enhancement and bugfixes
Browse files Browse the repository at this point in the history
* Fixed apache#1116 apache#1120 apache#1121 apache#1122 apache#1141 apache#1125 

* DubboConfigConfiguration's Single and Multiple to be public classes

* @DubboComponentScan is compatible with Spring @service completely

* @service and @reference issues on <dubbo:annotation>

* To fix an issue on <dubbo:annotation> when id attribute is absent

* To change the prefixes of properties when @EnableDubboConfig binds
multiple Config Bean
  • Loading branch information
mercyblitz authored and chickenlj committed Jan 22, 2018
1 parent 66486e4 commit c59adee
Show file tree
Hide file tree
Showing 18 changed files with 303 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
Expand Down Expand Up @@ -258,6 +259,17 @@ public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}


/**
* Gets all beans of {@link ReferenceBean}
*
* @return non-null {@link Collection}
* @since 2.5.9
*/
public Collection<ReferenceBean<?>> getReferenceBeans() {
return this.referenceBeansCache.values();
}

/**
* {@link Reference} {@link Method} {@link InjectionMetadata.InjectedElement}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
import org.springframework.beans.factory.support.*;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.*;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.filter.AnnotationTypeFilter;
Expand All @@ -36,7 +39,6 @@
import java.util.*;

import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition;
import static org.springframework.beans.factory.support.BeanDefinitionReaderUtils.registerWithGeneratedName;
import static org.springframework.context.annotation.AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR;
import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
import static org.springframework.util.ClassUtils.resolveClassName;
Expand Down Expand Up @@ -77,7 +79,13 @@ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) t

Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);

registerServiceBeans(resolvedPackagesToScan, registry);
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
registerServiceBeans(resolvedPackagesToScan, registry);
} else {
if (logger.isWarnEnabled()) {
logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
}
}

}

Expand All @@ -101,24 +109,17 @@ private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegi

for (String packageToScan : packagesToScan) {

Set<BeanDefinitionHolder> beanDefinitionHolders = scanner.doScan(packageToScan);
// Registers @Service Bean first
scanner.scan(packageToScan);

if (CollectionUtils.isEmpty(beanDefinitionHolders)) {

if (logger.isInfoEnabled()) {
logger.info("No Spring Bean annotating Dubbo's @Service was found in Spring BeanFactory , " +
"it maybe that some bean was also annotated @Component .");
logger.info("It will try to find all Bean types annotating Dubbo's @Service from all Bean Definitions");
}

beanDefinitionHolders = findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);

}
// Finds all BeanDefinitionHolders of @Service whether @ComponentScan scans or not.
Set<BeanDefinitionHolder> beanDefinitionHolders =
findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);

if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {

for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
registerServiceBean(beanDefinitionHolder, registry);
registerServiceBean(beanDefinitionHolder, registry, scanner);
}

if (logger.isInfoEnabled()) {
Expand All @@ -130,7 +131,8 @@ private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegi
} else {

if (logger.isWarnEnabled()) {
logger.warn("No Spring Bean annotating Dubbo's @Service was found in Spring BeanFactory");
logger.warn("No Spring Bean annotating Dubbo's @Service was found under package["
+ packageToScan + "]");
}

}
Expand Down Expand Up @@ -214,22 +216,58 @@ private Set<BeanDefinitionHolder> findServiceBeanDefinitionHolders(
*
* @param beanDefinitionHolder
* @param registry
* @param scanner
* @see ServiceBean
* @see BeanDefinition
*/
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry) {
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
DubboClassPathBeanDefinitionScanner scanner) {

Class<?> beanClass = resolveClass(beanDefinitionHolder);

Service service = findAnnotation(beanClass, Service.class);

Class<?> interfaceClass = resolveServiceInterfaceClass(beanClass, service);

String beanName = beanDefinitionHolder.getBeanName();
String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();

AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(service, interfaceClass, annotatedServiceBeanName);

// ServiceBean Bean name
String beanName = generateServiceBeanName(interfaceClass, annotatedServiceBeanName);

AbstractBeanDefinition serviceBeanDefinition = buildServiceBeanDefinition(service, interfaceClass, beanName);
if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean
registry.registerBeanDefinition(beanName, serviceBeanDefinition);

if (logger.isInfoEnabled()) {
logger.warn("The BeanDefinition[" + serviceBeanDefinition +
"] of ServiceBean has been registered with name : " + beanName);
}

registerWithGeneratedName(serviceBeanDefinition, registry);
} else {

if (logger.isWarnEnabled()) {
logger.warn("The Duplicated BeanDefinition[" + serviceBeanDefinition +
"] of ServiceBean[ bean name : " + beanName +
"] was be found , Did @DubboComponentScan scan to same package in many times?");
}

}

}

/**
* Generates the bean name of {@link ServiceBean}
*
* @param interfaceClass the class of interface annotated {@link Service}
* @param annotatedServiceBeanName the bean name of annotated {@link Service}
* @return ServiceBean@interfaceClassName#annotatedServiceBeanName
* @since 2.5.9
*/
private String generateServiceBeanName(Class<?> interfaceClass, String annotatedServiceBeanName) {

return "ServiceBean@" + interfaceClass.getName() + "#" + annotatedServiceBeanName;

}

Expand Down Expand Up @@ -289,8 +327,10 @@ private Class<?> resolveClass(BeanDefinition beanDefinition) {
private Set<String> resolvePackagesToScan(Set<String> packagesToScan) {
Set<String> resolvedPackagesToScan = new LinkedHashSet<String>(packagesToScan.size());
for (String packageToScan : packagesToScan) {
String resolvedPackageToScan = environment.resolvePlaceholders(packageToScan);
resolvedPackagesToScan.add(resolvedPackageToScan);
if (StringUtils.hasText(packageToScan)) {
String resolvedPackageToScan = environment.resolvePlaceholders(packageToScan.trim());
resolvedPackagesToScan.add(resolvedPackageToScan);
}
}
return resolvedPackagesToScan;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
package com.alibaba.dubbo.config.spring.context.annotation;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
Expand Down Expand Up @@ -60,5 +61,8 @@ public Set<BeanDefinitionHolder> doScan(String... basePackages) {
return super.doScan(basePackages);
}

public boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
return super.checkCandidate(beanName, beanDefinition);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -48,23 +48,23 @@ public class DubboConfigConfiguration {
@EnableDubboConfigBinding(prefix = "dubbo.provider", type = ProviderConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.consumer", type = ConsumerConfig.class)
})
static class Single {
public static class Single {

}

/**
* Multiple Dubbo {@link AbstractConfig Config} Bean Binding
*/
@EnableDubboConfigBindings({
@EnableDubboConfigBinding(prefix = "dubbo.application", type = ApplicationConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.module", type = ModuleConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.registry", type = RegistryConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.protocol", type = ProtocolConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.monitor", type = MonitorConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.provider", type = ProviderConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.consumer", type = ConsumerConfig.class, multiple = true)
@EnableDubboConfigBinding(prefix = "dubbo.applications", type = ApplicationConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.modules", type = ModuleConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.registries", type = RegistryConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.protocols", type = ProtocolConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.monitors", type = MonitorConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.providers", type = ProviderConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.consumers", type = ConsumerConfig.class, multiple = true)
})
static class Multiple {
public static class Multiple {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
import java.lang.annotation.*;

/**
* Equals {@link EnableDubboConfigBinding} for :
* As a convenient and multiple {@link EnableDubboConfigBinding}
* in default behavior , is equal to single bean bindings with below convention prefixes of properties:
* <ul>
* <li>{@link ApplicationConfig} binding to property : "dubbo.application"</li>
* <li>{@link ModuleConfig} binding to property : "dubbo.module"</li>
Expand All @@ -32,6 +33,17 @@
* <li>{@link ProviderConfig} binding to property : "dubbo.provider"</li>
* <li>{@link ConsumerConfig} binding to property : "dubbo.consumer"</li>
* </ul>
* <p>
* In contrast, on multiple bean bindings that requires to set {@link #multiple()} to be <code>true</code> :
* <ul>
* <li>{@link ApplicationConfig} binding to property : "dubbo.applications"</li>
* <li>{@link ModuleConfig} binding to property : "dubbo.modules"</li>
* <li>{@link RegistryConfig} binding to property : "dubbo.registries"</li>
* <li>{@link ProtocolConfig} binding to property : "dubbo.protocols"</li>
* <li>{@link MonitorConfig} binding to property : "dubbo.monitors"</li>
* <li>{@link ProviderConfig} binding to property : "dubbo.providers"</li>
* <li>{@link ConsumerConfig} binding to property : "dubbo.consumers"</li>
* </ul>
*
* @see EnableDubboConfigBinding
* @see DubboConfigConfiguration
Expand All @@ -49,6 +61,7 @@
* It indicates whether binding to multiple Spring Beans.
*
* @return the default value is <code>false</code>
* @revised 2.5.9
*/
boolean multiple() default false;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.alibaba.dubbo.config.spring.schema;

import com.alibaba.dubbo.config.spring.AnnotationBean;
import com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
import com.alibaba.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor;
import com.alibaba.dubbo.config.spring.util.BeanRegistrar;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;

import static org.springframework.util.StringUtils.commaDelimitedListToStringArray;
import static org.springframework.util.StringUtils.trimArrayElements;

/**
* {@link AnnotationBean} {@link BeanDefinitionParser}
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @see ServiceAnnotationBeanPostProcessor
* @see ReferenceAnnotationBeanPostProcessor
* @since 2.5.9
*/
public class AnnotationBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

/**
* parse
* <prev>
* &lt;dubbo:annotation package="" /&gt;
* </prev>
*
* @param element
* @param parserContext
* @param builder
*/
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {

String packageToScan = element.getAttribute("package");

String[] packagesToScan = trimArrayElements(commaDelimitedListToStringArray(packageToScan));

builder.addConstructorArgValue(packagesToScan);

builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

// Registers ReferenceAnnotationBeanPostProcessor
registerReferenceAnnotationBeanPostProcessor(parserContext.getRegistry());

}

protected boolean shouldGenerateIdAsFallback() {
return true;
}

/**
* Registers {@link ReferenceAnnotationBeanPostProcessor} into {@link BeanFactory}
*
* @param registry {@link BeanDefinitionRegistry}
*/
private void registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) {

// Register @Reference Annotation Bean Processor
BeanRegistrar.registerInfrastructureBean(registry,
ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);

}

protected Class<?> getBeanClass(Element element) {
return ServiceAnnotationBeanPostProcessor.class;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import com.alibaba.dubbo.common.Version;
import com.alibaba.dubbo.config.*;
import com.alibaba.dubbo.config.spring.AnnotationBean;
import com.alibaba.dubbo.config.spring.ReferenceBean;
import com.alibaba.dubbo.config.spring.ServiceBean;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
Expand All @@ -44,7 +43,7 @@ public void init() {
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}

}

0 comments on commit c59adee

Please sign in to comment.