Skip to content

Commit

Permalink
Spring package scan compatibility, support both alibaba Service and a…
Browse files Browse the repository at this point in the history
…pache Service. (#4375)

fixes #4330
  • Loading branch information
mercyblitz authored and chickenlj committed Jun 26, 2019
1 parent e1ce4bc commit acae8d9
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 84 deletions.
1 change: 1 addition & 0 deletions dubbo-config/dubbo-config-spring/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -128,5 +128,6 @@
<artifactId>tomcat-embed-core</artifactId>
<scope>test</scope>
</dependency>

</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
Expand All @@ -61,10 +61,12 @@
import java.util.Set;

import static org.apache.dubbo.config.spring.beans.factory.annotation.ServiceBeanNameBuilder.create;
import static org.apache.dubbo.config.spring.util.AnnotationUtils.resolveServiceInterfaceClass;
import static org.apache.dubbo.config.spring.util.ObjectUtils.of;
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition;
import static org.springframework.context.annotation.AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR;
import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes;
import static org.springframework.util.ClassUtils.resolveClassName;

/**
Expand Down Expand Up @@ -132,6 +134,14 @@ private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegi

scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class));

/**
* Add the compatibility for legacy Dubbo's @Service
*
* The issue : https://github.com/apache/dubbo/issues/4330
* @since 2.7.3
*/
scanner.addIncludeFilter(new AnnotationTypeFilter(com.alibaba.dubbo.config.annotation.Service.class));

for (String packageToScan : packagesToScan) {

// Registers @Service Bean first
Expand Down Expand Up @@ -250,17 +260,22 @@ private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, Bean

Class<?> beanClass = resolveClass(beanDefinitionHolder);

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

Class<?> interfaceClass = resolveServiceInterfaceClass(beanClass, service);
/**
* The {@link AnnotationAttributes} of @Service annotation
*/
AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes(service, false, false);

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

String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();

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

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

if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean
registry.registerBeanDefinition(beanName, serviceBeanDefinition);
Expand All @@ -282,58 +297,37 @@ private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, Bean

}


/**
* Find the {@link Annotation annotation} of @Service
*
* @param beanClass the {@link Class class} of Bean
* @return <code>null</code> if not found
* @since 2.7.3
*/
private Annotation findServiceAnnotation(Class<?> beanClass) {
Annotation service = findAnnotation(beanClass, Service.class);
if (service == null) {
service = findAnnotation(beanClass, com.alibaba.dubbo.config.annotation.Service.class);
}
return service;
}

/**
* Generates the bean name of {@link ServiceBean}
*
* @param service
* @param interfaceClass the class of interface annotated {@link Service}
* @param serviceAnnotationAttributes
* @param interfaceClass the class of interface annotated {@link Service}
* @return ServiceBean@interfaceClassName#annotatedServiceBeanName
* @since 2.5.9
* @since 2.7.3
*/
private String generateServiceBeanName(Service service, Class<?> interfaceClass) {
ServiceBeanNameBuilder builder = create(service, interfaceClass, environment);

private String generateServiceBeanName(AnnotationAttributes serviceAnnotationAttributes, Class<?> interfaceClass) {
ServiceBeanNameBuilder builder = create(interfaceClass, environment)
.group(serviceAnnotationAttributes.getString("group"))
.version(serviceAnnotationAttributes.getString("version"));
return builder.build();
}

private Class<?> resolveServiceInterfaceClass(Class<?> annotatedServiceBeanClass, Service service) {

Class<?> interfaceClass = service.interfaceClass();

if (void.class.equals(interfaceClass)) {

interfaceClass = null;

String interfaceClassName = service.interfaceName();

if (StringUtils.hasText(interfaceClassName)) {
if (ClassUtils.isPresent(interfaceClassName, classLoader)) {
interfaceClass = resolveClassName(interfaceClassName, classLoader);
}
}

}

if (interfaceClass == null) {
// Find all interfaces from the annotated class
// To resolve an issue : https://github.com/apache/dubbo/issues/3251
Class<?>[] allInterfaces = ClassUtils.getAllInterfacesForClass(annotatedServiceBeanClass);

if (allInterfaces.length > 0) {
interfaceClass = allInterfaces[0];
}

}

Assert.notNull(interfaceClass,
"@Service interfaceClass() or interfaceName() or interface class must be present!");

Assert.isTrue(interfaceClass.isInterface(),
"The type that was annotated @Service is not an interface!");

return interfaceClass;
}

private Class<?> resolveClass(BeanDefinitionHolder beanDefinitionHolder) {

BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();
Expand Down Expand Up @@ -361,7 +355,19 @@ private Set<String> resolvePackagesToScan(Set<String> packagesToScan) {
return resolvedPackagesToScan;
}

private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class<?> interfaceClass,
/**
* Build the {@link AbstractBeanDefinition Bean Definition}
*
* @param serviceAnnotation
* @param serviceAnnotationAttributes
* @param interfaceClass
* @param annotatedServiceBeanName
* @return
* @since 2.7.3
*/
private AbstractBeanDefinition buildServiceBeanDefinition(Annotation serviceAnnotation,
AnnotationAttributes serviceAnnotationAttributes,
Class<?> interfaceClass,
String annotatedServiceBeanName) {

BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);
Expand All @@ -373,43 +379,43 @@ private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class
String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol",
"interface", "interfaceName", "parameters");

propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(service, environment, ignoreAttributeNames));
propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(serviceAnnotation, environment, ignoreAttributeNames));

// References "ref" property to annotated-@Service Bean
addPropertyReference(builder, "ref", annotatedServiceBeanName);
// Set interface
builder.addPropertyValue("interface", interfaceClass.getName());
// Convert parameters into map
builder.addPropertyValue("parameters", convertParameters(service.parameters()));
builder.addPropertyValue("parameters", convertParameters(serviceAnnotationAttributes.getStringArray("parameters")));

/**
* Add {@link org.apache.dubbo.config.ProviderConfig} Bean reference
*/
String providerConfigBeanName = service.provider();
String providerConfigBeanName = serviceAnnotationAttributes.getString("provider");
if (StringUtils.hasText(providerConfigBeanName)) {
addPropertyReference(builder, "provider", providerConfigBeanName);
}

/**
* Add {@link org.apache.dubbo.config.MonitorConfig} Bean reference
*/
String monitorConfigBeanName = service.monitor();
String monitorConfigBeanName = serviceAnnotationAttributes.getString("monitor");
if (StringUtils.hasText(monitorConfigBeanName)) {
addPropertyReference(builder, "monitor", monitorConfigBeanName);
}

/**
* Add {@link org.apache.dubbo.config.ApplicationConfig} Bean reference
*/
String applicationConfigBeanName = service.application();
String applicationConfigBeanName = serviceAnnotationAttributes.getString("application");
if (StringUtils.hasText(applicationConfigBeanName)) {
addPropertyReference(builder, "application", applicationConfigBeanName);
}

/**
* Add {@link org.apache.dubbo.config.ModuleConfig} Bean reference
*/
String moduleConfigBeanName = service.module();
String moduleConfigBeanName = serviceAnnotationAttributes.getString("module");
if (StringUtils.hasText(moduleConfigBeanName)) {
addPropertyReference(builder, "module", moduleConfigBeanName);
}
Expand All @@ -418,7 +424,7 @@ private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class
/**
* Add {@link org.apache.dubbo.config.RegistryConfig} Bean reference
*/
String[] registryConfigBeanNames = service.registry();
String[] registryConfigBeanNames = serviceAnnotationAttributes.getStringArray("registry");

List<RuntimeBeanReference> registryRuntimeBeanReferences = toRuntimeBeanReferences(registryConfigBeanNames);

Expand All @@ -429,7 +435,7 @@ private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class
/**
* Add {@link org.apache.dubbo.config.ProtocolConfig} Bean reference
*/
String[] protocolConfigBeanNames = service.protocol();
String[] protocolConfigBeanNames = serviceAnnotationAttributes.getStringArray("protocol");

List<RuntimeBeanReference> protocolRuntimeBeanReferences = toRuntimeBeanReferences(protocolConfigBeanNames);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.dubbo.config.spring.ServiceBean;

import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;

import static org.apache.dubbo.config.spring.util.AnnotationUtils.resolveInterfaceName;
import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes;

/**
* Dubbo {@link Service @Service} Bean Builder
Expand All @@ -39,6 +41,7 @@ public class ServiceBeanNameBuilder {

private static final String SEPARATOR = ":";

// Required
private final String interfaceClassName;

private final Environment environment;
Expand All @@ -48,42 +51,47 @@ public class ServiceBeanNameBuilder {

private String group;

private ServiceBeanNameBuilder(Class<?> interfaceClass, Environment environment) {
this(interfaceClass.getName(), environment);
}

private ServiceBeanNameBuilder(String interfaceClassName, Environment environment) {
this.interfaceClassName = interfaceClassName;
this.environment = environment;
}

private ServiceBeanNameBuilder(Class<?> interfaceClass, Environment environment) {
this(interfaceClass.getName(), environment);
}

private ServiceBeanNameBuilder(Service service, Class<?> interfaceClass, Environment environment) {
this(resolveInterfaceName(service, interfaceClass), environment);
this.group(service.group());
this.version(service.version());
private ServiceBeanNameBuilder(AnnotationAttributes attributes, Class<?> defaultInterfaceClass, Environment environment) {
this(resolveInterfaceName(attributes, defaultInterfaceClass), environment);
this.group(attributes.getString("group"));
this.version(attributes.getString("version"));
}

private ServiceBeanNameBuilder(Reference reference, Class<?> interfaceClass, Environment environment) {
this(resolveInterfaceName(reference, interfaceClass), environment);
this.group(reference.group());
this.version(reference.version());
/**
* @param attributes
* @param defaultInterfaceClass
* @param environment
* @return
* @since 2.7.3
*/
public static ServiceBeanNameBuilder create(AnnotationAttributes attributes, Class<?> defaultInterfaceClass, Environment environment) {
return new ServiceBeanNameBuilder(attributes, defaultInterfaceClass, environment);
}

public static ServiceBeanNameBuilder create(Class<?> interfaceClass, Environment environment) {
return new ServiceBeanNameBuilder(interfaceClass, environment);
}

public static ServiceBeanNameBuilder create(Service service, Class<?> interfaceClass, Environment environment) {
return new ServiceBeanNameBuilder(service, interfaceClass, environment);
return create(getAnnotationAttributes(service, false, false), interfaceClass, environment);
}

public static ServiceBeanNameBuilder create(Reference reference, Class<?> interfaceClass, Environment environment) {
return new ServiceBeanNameBuilder(reference, interfaceClass, environment);
return create(getAnnotationAttributes(reference, false, false), interfaceClass, environment);
}

private static void append(StringBuilder builder, String value) {
if (StringUtils.hasText(value)) {
builder.append(value).append(SEPARATOR);
builder.append(SEPARATOR).append(value);
}
}

Expand All @@ -98,14 +106,14 @@ public ServiceBeanNameBuilder version(String version) {
}

public String build() {
StringBuilder beanNameBuilder = new StringBuilder("ServiceBean").append(SEPARATOR);
StringBuilder beanNameBuilder = new StringBuilder("ServiceBean");
// Required
append(beanNameBuilder, interfaceClassName);
// Optional
append(beanNameBuilder, version);
append(beanNameBuilder, group);
// Build and remove last ":"
String rawBeanName = beanNameBuilder.substring(0, beanNameBuilder.length() - 1);
String rawBeanName = beanNameBuilder.toString();
// Resolve placeholders
return environment.resolvePlaceholders(rawBeanName);
}
Expand Down
Loading

0 comments on commit acae8d9

Please sign in to comment.