You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by li...@apache.org on 2021/06/10 16:08:31 UTC
[dubbo] branch 3.0 updated: Support service annotation work with
java config bean (#8011)
This is an automated email from the ASF dual-hosted git repository.
liujun pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/3.0 by this push:
new f07640f Support service annotation work with java config bean (#8011)
f07640f is described below
commit f07640fc7455726c841b009492dc5edf5f11c6d1
Author: Gong Dewei <ky...@qq.com>
AuthorDate: Fri Jun 11 00:07:12 2021 +0800
Support service annotation work with java config bean (#8011)
---
.../alibaba/dubbo/config/annotation/Service.java | 2 +-
.../apache/dubbo/common/utils/AnnotationUtils.java | 54 +++++
.../org/apache/dubbo/config/AbstractConfig.java | 61 ++---
.../org/apache/dubbo/config/ProviderConfig.java | 6 -
.../dubbo/config/annotation/DubboService.java | 31 ++-
.../apache/dubbo/config/annotation/Service.java | 2 +-
.../apache/dubbo/config/context/ConfigManager.java | 11 +-
.../dubbo/common/utils/AnnotationUtilsTest.java | 24 ++
dubbo-config/dubbo-config-spring/pom.xml | 2 +
.../org/apache/dubbo/config/spring/Constants.java | 11 +
.../apache/dubbo/config/spring/ServiceBean.java | 2 +-
.../AbstractAnnotationBeanPostProcessor.java | 15 +-
.../ReferenceAnnotationBeanPostProcessor.java | 20 +-
.../annotation/ServiceAnnotationPostProcessor.java | 265 +++++++++++++++------
.../factory/annotation/ServicePackagesHolder.java | 86 +++++++
.../DubboInfraBeanRegisterPostProcessor.java | 2 +-
.../annotation/DubboComponentScanRegistrar.java | 6 +-
.../spring/schema/DubboBeanDefinitionParser.java | 4 +-
.../config/spring/util/DubboAnnotationUtils.java | 25 +-
.../dubbo/config/spring/util/DubboBeanUtils.java | 4 +
.../dubbo/config/spring/JavaConfigBeanTest.java | 38 +--
.../ServiceAnnotationPostProcessorTest.java | 11 +-
.../extension/SpringExtensionFactoryTest.java | 17 +-
dubbo-dependencies-bom/pom.xml | 1 +
...bstractRequestAnnotationParameterProcessor.java | 2 +-
.../boot/autoconfigure/DubboAutoConfiguration.java | 2 -
26 files changed, 522 insertions(+), 182 deletions(-)
diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/config/annotation/Service.java b/dubbo-common/src/main/java/com/alibaba/dubbo/config/annotation/Service.java
index 564575b..5de941f 100644
--- a/dubbo-common/src/main/java/com/alibaba/dubbo/config/annotation/Service.java
+++ b/dubbo-common/src/main/java/com/alibaba/dubbo/config/annotation/Service.java
@@ -35,7 +35,7 @@ import java.lang.annotation.Target;
@Deprecated
@Documented
@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
+@Target({ElementType.TYPE, ElementType.METHOD})
@Inherited
public @interface Service {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AnnotationUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AnnotationUtils.java
index 8da5f1d..ba2da5b 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AnnotationUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AnnotationUtils.java
@@ -25,9 +25,11 @@ import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
@@ -479,4 +481,56 @@ public interface AnnotationUtils {
Method method = findMethod(annotationType, attributeName);
return (T) (method == null ? null : method.getDefaultValue());
}
+
+ /**
+ * Filter default value of Annotation type
+ * @param annotationType annotation type from {@link Annotation#annotationType()}
+ * @param attributes
+ * @return
+ */
+ static Map<String, Object> filterDefaultValues(Class<? extends Annotation> annotationType, Map<String, Object> attributes) {
+ Map<String, Object> filteredAttributes = new LinkedHashMap<>(attributes.size());
+ attributes.forEach((key,val) -> {
+ if (!Objects.deepEquals(val, getDefaultValue(annotationType, key))) {
+ filteredAttributes.put(key, val);
+ }
+ });
+ return filteredAttributes;
+ }
+
+ /**
+ * Filter default value of Annotation type
+ * @param annotation
+ * @param attributes
+ * @return
+ */
+ static Map<String, Object> filterDefaultValues(Annotation annotation, Map<String, Object> attributes) {
+ return filterDefaultValues(annotation.annotationType(), attributes);
+ }
+
+ /**
+ * Get attributes of annotation
+ * @param annotation
+ * @return
+ */
+ static Map<String, Object> getAttributes(Annotation annotation, boolean filterDefaultValue) {
+ Class<?> annotationType = annotation.annotationType();
+ Method[] methods = annotationType.getMethods();
+ Map<String, Object> attributes = new LinkedHashMap<>(methods.length);
+ for (Method method : methods) {
+ try {
+ if (method.getDeclaringClass() == Annotation.class) {
+ continue;
+ }
+ String name = method.getName();
+ Object value = method.invoke(annotation);
+ if (!filterDefaultValue || !Objects.deepEquals(value, method.getDefaultValue())) {
+ attributes.put(name, value);
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("get attribute value of annotation failed: " + method, e);
+ }
+ }
+ return attributes;
+ }
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java
index 7d9007f..5130e0e 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java
@@ -86,7 +86,7 @@ public abstract class AbstractConfig implements Serializable {
protected final AtomicBoolean refreshed = new AtomicBoolean(false);
/**
- * Is default or not
+ * Is default config or not
*/
protected Boolean isDefault;
@@ -606,6 +606,36 @@ public abstract class AbstractConfig implements Serializable {
return refreshed.get();
}
+ /**
+ * FIXME check @Parameter(required=true) and any conditions that need to match.
+ */
+ @Parameter(excluded = true, attribute = false)
+ public boolean isValid() {
+ return true;
+ }
+
+ @Parameter(excluded = true, attribute = false)
+ public Boolean isDefault() {
+ return isDefault;
+ }
+
+ public void setDefault(Boolean isDefault) {
+ this.isDefault = isDefault;
+ }
+
+ /**
+ * Add {@link AbstractConfig instance} into {@link ConfigManager}
+ * <p>
+ * Current method will invoked by Spring or Java EE container automatically, or should be triggered manually.
+ *
+ * @see ConfigManager#addConfig(AbstractConfig)
+ * @since 2.7.5
+ */
+ @PostConstruct
+ public void addIntoConfigManager() {
+ ApplicationModel.getConfigManager().addConfig(this);
+ }
+
@Override
public String toString() {
try {
@@ -658,15 +688,6 @@ public abstract class AbstractConfig implements Serializable {
return fieldNamesCache.computeIfAbsent(configClass, ReflectUtils::getAllFieldNames);
}
- /**
- * FIXME check @Parameter(required=true) and any conditions that need to match.
- */
- @Parameter(excluded = true, attribute = false)
- public boolean isValid() {
- return true;
- }
-
-
@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != this.getClass()) {
@@ -708,19 +729,6 @@ public abstract class AbstractConfig implements Serializable {
return true;
}
- /**
- * Add {@link AbstractConfig instance} into {@link ConfigManager}
- * <p>
- * Current method will invoked by Spring or Java EE container automatically, or should be triggered manually.
- *
- * @see ConfigManager#addConfig(AbstractConfig)
- * @since 2.7.5
- */
- @PostConstruct
- public void addIntoConfigManager() {
- ApplicationModel.getConfigManager().addConfig(this);
- }
-
@Override
public int hashCode() {
int hashCode = 1;
@@ -748,11 +756,4 @@ public abstract class AbstractConfig implements Serializable {
return hashCode;
}
- public Boolean isDefault() {
- return isDefault;
- }
-
- public void setDefault(Boolean isDefault) {
- this.isDefault = isDefault;
- }
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/ProviderConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/ProviderConfig.java
index 62eb377..9e0a2dd 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/ProviderConfig.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/ProviderConfig.java
@@ -159,12 +159,6 @@ public class ProviderConfig extends AbstractServiceConfig {
this.protocols = new ArrayList<>(Arrays.asList(new ProtocolConfig(protocol)));
}
- @Override
- @Parameter(excluded = true)
- public Boolean isDefault() {
- return isDefault;
- }
-
@Parameter(excluded = true)
public String getHost() {
return host;
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/annotation/DubboService.java b/dubbo-common/src/main/java/org/apache/dubbo/config/annotation/DubboService.java
index ebeb2ea..ba9fc3f 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/annotation/DubboService.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/annotation/DubboService.java
@@ -27,13 +27,40 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
- * Class-level annotation used for declaring Dubbo service
+ * Class-level annotation used for declaring Dubbo service.
+ * <p/>
+ * <b>1. Using with java config bean:</b>
+ * <p/>
+ * <b>This usage is recommended</b>.<br/>
+ * It is more flexible on bean methods than on implementation classes, and is more compatible with Spring.
+ * <pre>
+ * @Configuration
+ * class ProviderConfiguration {
+ *
+ * @Bean
+ * @DubboService(group="demo")
+ * public DemoService demoServiceImpl() {
+ * return new DemoServiceImpl();
+ * }
+ * }
+ * </pre>
+ *
+ * <b>2. Using on implementation class of service: </b>
+ * <pre>
+ * @DubboService(group="demo")
+ * public class DemoServiceImpl implements DemoService {
+ * ...
+ * }
+ * </pre>
+ *
+ * This usage causes the implementation class to rely on the Dubbo module.
+ *
*
* @since 2.7.7
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
+@Target({ElementType.TYPE, ElementType.METHOD})
@Inherited
public @interface DubboService {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/annotation/Service.java b/dubbo-common/src/main/java/org/apache/dubbo/config/annotation/Service.java
index 1a02bf1..e712e4a 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/annotation/Service.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/annotation/Service.java
@@ -33,7 +33,7 @@ import java.lang.annotation.Target;
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
+@Target({ElementType.TYPE, ElementType.METHOD})
@Inherited
@Deprecated
public @interface Service {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java
index b9ce345..2ac5969 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java
@@ -676,16 +676,11 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
}
static <C extends AbstractConfig> Boolean isDefaultConfig(C config) {
- // If no isDefault() method, it is considered that each can be used as default
- if (!ReflectUtils.hasMethod(config.getClass(), "isDefault")) {
- return true;
- }
- Boolean isDefault = ReflectUtils.getProperty(config, "isDefault");
- return isDefault;
+ return config.isDefault();
}
static <C extends AbstractConfig> List<C> getDefaultConfigs(Map<String, C> configsMap) {
- // find isDefault() == TRUE
+ // find isDefault() == true
List<C> list = configsMap.values()
.stream()
.filter(c -> TRUE.equals(ConfigManager.isDefaultConfig(c)))
@@ -700,6 +695,8 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
.filter(c -> ConfigManager.isDefaultConfig(c) == null)
.collect(Collectors.toList());
return list;
+
+ // exclude isDefault() == false
}
}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/AnnotationUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/AnnotationUtilsTest.java
index 86dff96..7c43465 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/AnnotationUtilsTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/AnnotationUtilsTest.java
@@ -31,9 +31,11 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import static java.util.Arrays.asList;
import static org.apache.dubbo.common.utils.AnnotationUtils.excludedType;
+import static org.apache.dubbo.common.utils.AnnotationUtils.filterDefaultValues;
import static org.apache.dubbo.common.utils.AnnotationUtils.findAnnotation;
import static org.apache.dubbo.common.utils.AnnotationUtils.findMetaAnnotation;
import static org.apache.dubbo.common.utils.AnnotationUtils.findMetaAnnotations;
@@ -41,7 +43,9 @@ import static org.apache.dubbo.common.utils.AnnotationUtils.getAllDeclaredAnnota
import static org.apache.dubbo.common.utils.AnnotationUtils.getAllMetaAnnotations;
import static org.apache.dubbo.common.utils.AnnotationUtils.getAnnotation;
import static org.apache.dubbo.common.utils.AnnotationUtils.getAttribute;
+import static org.apache.dubbo.common.utils.AnnotationUtils.getAttributes;
import static org.apache.dubbo.common.utils.AnnotationUtils.getDeclaredAnnotations;
+import static org.apache.dubbo.common.utils.AnnotationUtils.getDefaultValue;
import static org.apache.dubbo.common.utils.AnnotationUtils.getMetaAnnotations;
import static org.apache.dubbo.common.utils.AnnotationUtils.getValue;
import static org.apache.dubbo.common.utils.AnnotationUtils.isAnnotationPresent;
@@ -101,6 +105,26 @@ public class AnnotationUtilsTest {
}
@Test
+ public void testGetAttributesMap() {
+ Annotation annotation = A.class.getAnnotation(Service.class);
+ Map<String, Object> attributes = getAttributes(annotation, false);
+ assertEquals("java.lang.CharSequence", attributes.get("interfaceName"));
+ assertEquals(CharSequence.class, attributes.get("interfaceClass"));
+ assertEquals("", attributes.get("group"));
+ assertEquals(getDefaultValue(annotation, "export"), attributes.get("export"));
+
+ Map<String, Object> filteredAttributes = filterDefaultValues(annotation, attributes);
+ assertEquals(2, filteredAttributes.size());
+ assertEquals("java.lang.CharSequence", filteredAttributes.get("interfaceName"));
+ assertEquals(CharSequence.class, filteredAttributes.get("interfaceClass"));
+ assertFalse(filteredAttributes.containsKey("group"));
+ assertFalse(filteredAttributes.containsKey("export"));
+
+ Map<String, Object> nonDefaultAttributes = getAttributes(annotation, true);
+ assertEquals(nonDefaultAttributes, filteredAttributes);
+ }
+
+ @Test
public void testGetValue() {
Adaptive adaptive = A.class.getAnnotation(Adaptive.class);
String[] value = getValue(adaptive);
diff --git a/dubbo-config/dubbo-config-spring/pom.xml b/dubbo-config/dubbo-config-spring/pom.xml
index 08ca2a9..2414579 100644
--- a/dubbo-config/dubbo-config-spring/pom.xml
+++ b/dubbo-config/dubbo-config-spring/pom.xml
@@ -28,6 +28,8 @@
<properties>
<skip_maven_deploy>false</skip_maven_deploy>
<spring-boot.version>2.3.1.RELEASE</spring-boot.version>
+ <!-- Uncomment spring_version property to check Spring 4.x compatibility -->
+ <!-- <spring_version>4.3.30.RELEASE</spring_version> -->
</properties>
<dependencies>
<dependency>
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/Constants.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/Constants.java
index d78285e..eec6100 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/Constants.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/Constants.java
@@ -31,4 +31,15 @@ public interface Constants {
*/
String REFERENCE_SOURCES = "referenceSources";
+ /**
+ * The name of an attribute that can be
+ * {@link org.springframework.core.AttributeAccessor#setAttribute set} on a
+ * {@link org.springframework.beans.factory.config.BeanDefinition} so that
+ * factory beans can signal their object type when it can't be deduced from
+ * the factory bean class.
+ * <p/>
+ * From FactoryBean.OBJECT_TYPE_ATTRIBUTE of Spring 5.2.
+ */
+ String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
+
}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java
index 52d45b0..b596568 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java
@@ -100,7 +100,7 @@ public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean
* @return {@link ServiceBean}'s name
* @since 2.6.5
*/
- @Parameter(excluded = true)
+ @Parameter(excluded = true, attribute = false)
public String getBeanName() {
return this.beanName;
}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationBeanPostProcessor.java
index 0771244..27caae2 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationBeanPostProcessor.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationBeanPostProcessor.java
@@ -241,7 +241,7 @@ public abstract class AbstractAnnotationBeanPostProcessor extends
private AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass) {
Collection<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> fieldElements = findFieldAnnotationMetadata(beanClass);
Collection<AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement> methodElements = findAnnotatedMethodMetadata(beanClass);
- return new AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
+ return new AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
}
protected AnnotatedInjectionMetadata findInjectionMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
@@ -249,11 +249,11 @@ public abstract class AbstractAnnotationBeanPostProcessor extends
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
- if (InjectionMetadata.needsRefresh(metadata, clazz)) {
+ if (needsRefreshInjectionMetadata(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
- if (InjectionMetadata.needsRefresh(metadata, clazz)) {
+ if (needsRefreshInjectionMetadata(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
@@ -270,6 +270,11 @@ public abstract class AbstractAnnotationBeanPostProcessor extends
return metadata;
}
+ // Use custom check method to compatible with Spring 4.x
+ private boolean needsRefreshInjectionMetadata(AnnotatedInjectionMetadata metadata, Class<?> clazz) {
+ return (metadata == null || metadata.needsRefresh(clazz));
+ }
+
@Override
public int getOrder() {
return order;
@@ -402,7 +407,7 @@ public abstract class AbstractAnnotationBeanPostProcessor extends
/**
* {@link Annotation Annotated} {@link InjectionMetadata} implementation
*/
- protected class AnnotatedInjectionMetadata extends InjectionMetadata {
+ protected static class AnnotatedInjectionMetadata extends InjectionMetadata {
private Class<?> targetClass;
private final Collection<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> fieldElements;
@@ -425,7 +430,7 @@ public abstract class AbstractAnnotationBeanPostProcessor extends
return methodElements;
}
- @Override
+ //@Override // since Spring 5.2.4
protected boolean needsRefresh(Class<?> clazz) {
if (this.targetClass == clazz) {
return false;
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java
index b4231f3..2cb397f 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java
@@ -34,7 +34,6 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.BeanCreationException;
-import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -47,7 +46,6 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationAttributes;
-import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.type.MethodMetadata;
import java.beans.PropertyDescriptor;
@@ -63,6 +61,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static com.alibaba.spring.util.AnnotationUtils.getAttribute;
+import static org.apache.dubbo.common.utils.AnnotationUtils.filterDefaultValues;
import static org.springframework.util.StringUtils.hasText;
/**
@@ -193,8 +192,8 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
// Extract beanClass from generic return type of java-config bean method: ReferenceBean<DemoService>
// see org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryBeanFromMethod
Class beanClass = getBeanFactory().getType(beanName);
+ MethodMetadata factoryMethodMetadata = beanDefinition.getFactoryMethodMetadata();
if (beanClass == null) {
- MethodMetadata factoryMethodMetadata = beanDefinition.getFactoryMethodMetadata();
String beanMethodSignature = factoryMethodMetadata.getDeclaringClassName()+"#"+factoryMethodMetadata.getMethodName()+"()";
throw new BeanCreationException("The ReferenceBean is missing necessary generic type, which returned by the @Bean method of Java-config class. " +
"The generic type of the returned ReferenceBean must be specified as the referenced interface type, " +
@@ -203,14 +202,14 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
// get dubbo reference annotation attributes
Map<String, Object> annotationAttributes = null;
- MergedAnnotations mergedAnnotations = beanDefinition.getFactoryMethodMetadata().getAnnotations();
- Class referenceAnnotationType = null;
// try all dubbo reference annotation types
for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
- if (mergedAnnotations.isPresent(annotationType)) {
- referenceAnnotationType = annotationType;
- annotationAttributes = mergedAnnotations.get(annotationType).filterDefaultValues().asMap();
- break;
+ if (factoryMethodMetadata.isAnnotated(annotationType.getName())) {
+ // Since Spring 5.2
+ // return factoryMethodMetadata.getAnnotations().get(annotationType).filterDefaultValues().asMap();
+ // Compatible with Spring 4.x
+ annotationAttributes = factoryMethodMetadata.getAnnotationAttributes(annotationType.getName());
+ annotationAttributes = filterDefaultValues(annotationType, annotationAttributes);
}
}
@@ -226,7 +225,6 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
String interfaceName = (String) attributes.get(ReferenceAttributes.INTERFACE);
// check beanClass and reference interface class
if (!StringUtils.isEquals(interfaceName, beanClass.getName()) && beanClass != GenericService.class) {
- MethodMetadata factoryMethodMetadata = beanDefinition.getFactoryMethodMetadata();
String beanMethodSignature = factoryMethodMetadata.getDeclaringClassName()+"#"+factoryMethodMetadata.getMethodName()+"()";
throw new BeanCreationException("The 'interfaceClass' or 'interfaceName' attribute value of @DubboReference annotation " +
"is inconsistent with the generic type of the ReferenceBean returned by the bean method. " +
@@ -468,7 +466,7 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
beanDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, id+"_decorated"));
// signal object type since Spring 5.2
- beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, interfaceClass);
+ beanDefinition.setAttribute(Constants.OBJECT_TYPE_ATTRIBUTE, interfaceClass);
beanDefinitionRegistry.registerBeanDefinition(referenceBeanName, beanDefinition);
logger.info("Register dubbo reference bean: "+referenceBeanName+" = "+referenceKey+" at "+member);
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationPostProcessor.java
index 79031cb..89ee841 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationPostProcessor.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationPostProcessor.java
@@ -16,22 +16,25 @@
*/
package org.apache.dubbo.config.spring.beans.factory.annotation;
+import com.alibaba.spring.util.AnnotationUtils;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ArrayUtils;
import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.config.Constants;
import org.apache.dubbo.config.MethodConfig;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.dubbo.config.annotation.Method;
import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.config.spring.ServiceBean;
-import org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener;
import org.apache.dubbo.config.spring.context.annotation.DubboClassPathBeanDefinitionScanner;
import org.apache.dubbo.config.spring.schema.AnnotationBeanDefinitionParser;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.BeanDefinitionStoreException;
+import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
@@ -43,49 +46,59 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
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.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
+import org.springframework.core.type.MethodMetadata;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
+import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.CollectionUtils;
+import java.io.IOException;
import java.lang.annotation.Annotation;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
-import static com.alibaba.spring.util.BeanRegistrar.registerInfrastructureBean;
import static com.alibaba.spring.util.ObjectUtils.of;
import static java.util.Arrays.asList;
+import static org.apache.dubbo.common.utils.AnnotationUtils.filterDefaultValues;
import static org.apache.dubbo.config.spring.beans.factory.annotation.ServiceBeanNameBuilder.create;
import static org.apache.dubbo.config.spring.util.DubboAnnotationUtils.resolveServiceInterfaceClass;
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.AnnotatedElementUtils.findMergedAnnotation;
-import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes;
import static org.springframework.util.ClassUtils.resolveClassName;
/**
- * {@link BeanFactoryPostProcessor} used for processing of {@link Service @Service} annotated classes. it's also the
- * infrastructure class of XML {@link BeanDefinitionParser} on <dubbbo:annotation />
+ * A {@link BeanFactoryPostProcessor} used for processing of {@link Service @Service} annotated classes and annotated bean in java config classes.
+ * It's also the infrastructure class of XML {@link BeanDefinitionParser} on <dubbbo:annotation />
+ *
*
* @see AnnotationBeanDefinitionParser
* @see BeanDefinitionRegistryPostProcessor
* @since 2.7.7
*/
public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware,
- ResourceLoaderAware, BeanClassLoaderAware {
+ ResourceLoaderAware, BeanClassLoaderAware, ApplicationContextAware {
+
+ public static final String BEAN_NAME = "dubboServiceAnnotationPostProcessor";
private final static List<Class<? extends Annotation>> serviceAnnotationTypes = asList(
// @since 2.7.7 Add the @DubboService , the issue : https://github.com/apache/dubbo/issues/6007
@@ -107,6 +120,11 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
private ClassLoader classLoader;
+ private BeanDefinitionRegistry registry;
+
+ private ServicePackagesHolder servicePackagesHolder;
+
+
public ServiceAnnotationPostProcessor(String... packagesToScan) {
this(asList(packagesToScan));
}
@@ -121,14 +139,12 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
-
- // @since 2.7.5
- registerInfrastructureBean(registry, DubboBootstrapApplicationListener.BEAN_NAME, DubboBootstrapApplicationListener.class);
+ this.registry = registry;
Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
- registerServiceBeans(resolvedPackagesToScan, registry);
+ scanServiceBeans(resolvedPackagesToScan, registry);
} else {
if (logger.isWarnEnabled()) {
logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
@@ -138,27 +154,35 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
}
/**
- * Registers Beans whose classes was annotated {@link Service}
+ * Scan and registers service beans whose classes was annotated {@link Service}
*
* @param packagesToScan The base packages to scan
* @param registry {@link BeanDefinitionRegistry}
*/
- private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
+ private void scanServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
DubboClassPathBeanDefinitionScanner scanner =
new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
-
scanner.setBeanNameGenerator(beanNameGenerator);
-
- // refactor @since 2.7.7
- serviceAnnotationTypes.forEach(annotationType -> {
+ for (Class<? extends Annotation> annotationType : serviceAnnotationTypes) {
scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));
- });
+ }
+
+ ScanExcludeFilter scanExcludeFilter = new ScanExcludeFilter();
+ scanner.addExcludeFilter(scanExcludeFilter);
for (String packageToScan : packagesToScan) {
+ // avoid duplicated scans
+ if (servicePackagesHolder.isPackageScanned(packageToScan)) {
+ if (logger.isInfoEnabled()) {
+ logger.info("Ignore package who has already bean scanned: " + packageToScan);
+ }
+ continue;
+ }
+
// Registers @Service Bean first
scanner.scan(packageToScan);
@@ -167,28 +191,27 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
-
- for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
- registerServiceBean(beanDefinitionHolder, registry, scanner);
- }
-
if (logger.isInfoEnabled()) {
- logger.info(beanDefinitionHolders.size() + " annotated Dubbo's @Service Components { " +
- beanDefinitionHolders +
- " } were scanned under package[" + packageToScan + "]");
+ List<String> serviceClasses = new ArrayList<>(beanDefinitionHolders.size());
+ for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
+ serviceClasses.add(beanDefinitionHolder.getBeanDefinition().getBeanClassName());
+ }
+ logger.info("Found " + beanDefinitionHolders.size() + " classes annotated by Dubbo @Service under package [" + packageToScan + "]: " + serviceClasses);
}
+ for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
+ processScannedBeanDefinition(beanDefinitionHolder, registry, scanner);
+ servicePackagesHolder.addScannedClass(beanDefinitionHolder.getBeanDefinition().getBeanClassName());
+ }
} else {
-
if (logger.isWarnEnabled()) {
- logger.warn("No Spring Bean annotating Dubbo's @Service was found under package["
- + packageToScan + "]");
+ logger.warn("No class annotated by Dubbo @Service was found under package ["
+ + packageToScan + "], ignore re-scanned classes: " + scanExcludeFilter.getExcludedCount());
}
-
}
+ servicePackagesHolder.addScannedPackage(packageToScan);
}
-
}
/**
@@ -270,17 +293,15 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
* @see ServiceBean
* @see BeanDefinition
*/
- private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
- DubboClassPathBeanDefinitionScanner scanner) {
+ private void processScannedBeanDefinition(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
+ DubboClassPathBeanDefinitionScanner scanner) {
Class<?> beanClass = resolveClass(beanDefinitionHolder);
Annotation service = findServiceAnnotation(beanClass);
- /**
- * The {@link AnnotationAttributes} of @Service annotation
- */
- AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes(service, false, false);
+ // The attributes of @Service annotation
+ Map<String, Object> serviceAnnotationAttributes = AnnotationUtils.getAttributes(service, true);
Class<?> interfaceClass = resolveServiceInterfaceClass(serviceAnnotationAttributes, beanClass);
@@ -290,26 +311,9 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
String beanName = generateServiceBeanName(serviceAnnotationAttributes, interfaceClass);
AbstractBeanDefinition serviceBeanDefinition =
- buildServiceBeanDefinition(beanName, service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
-
- if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean
- registry.registerBeanDefinition(beanName, serviceBeanDefinition);
-
- if (logger.isInfoEnabled()) {
- logger.info("The BeanDefinition[" + serviceBeanDefinition +
- "] of ServiceBean has been registered with name : " + beanName);
- }
-
- } else {
+ buildServiceBeanDefinition(serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
- //TODO throw exception
- 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?");
- }
-
- }
+ registerServiceBeanDefinition(beanName, serviceBeanDefinition, interfaceClass);
}
@@ -337,10 +341,10 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
* @return ServiceBean@interfaceClassName#annotatedServiceBeanName
* @since 2.7.3
*/
- private String generateServiceBeanName(AnnotationAttributes serviceAnnotationAttributes, Class<?> interfaceClass) {
+ private String generateServiceBeanName(Map<String, Object> serviceAnnotationAttributes, Class<?> interfaceClass) {
ServiceBeanNameBuilder builder = create(interfaceClass, environment)
- .group(serviceAnnotationAttributes.getString("group"))
- .version(serviceAnnotationAttributes.getString("version"));
+ .group((String) serviceAnnotationAttributes.get("group"))
+ .version((String) serviceAnnotationAttributes.get("version"));
return builder.build();
}
@@ -375,18 +379,15 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
* Build the {@link AbstractBeanDefinition Bean Definition}
*
*
- * @param beanName
- * @param serviceAnnotation
* @param serviceAnnotationAttributes
* @param interfaceClass
- * @param annotatedServiceBeanName
+ * @param refServiceBeanName
* @return
* @since 2.7.3
*/
- private AbstractBeanDefinition buildServiceBeanDefinition(String beanName, Annotation serviceAnnotation,
- AnnotationAttributes serviceAnnotationAttributes,
+ private AbstractBeanDefinition buildServiceBeanDefinition(Map<String, Object> serviceAnnotationAttributes,
Class<?> interfaceClass,
- String annotatedServiceBeanName) {
+ String refServiceBeanName) {
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);
@@ -397,16 +398,16 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol",
"interface", "interfaceName", "parameters");
- propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(serviceAnnotation, environment, ignoreAttributeNames));
+ propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(serviceAnnotationAttributes, environment, ignoreAttributeNames));
//set config id, for ConfigManager cache key
//builder.addPropertyValue("id", beanName);
// References "ref" property to annotated-@Service Bean
- addPropertyReference(builder, "ref", annotatedServiceBeanName);
+ addPropertyReference(builder, "ref", refServiceBeanName);
// Set interface
builder.addPropertyValue("interface", interfaceClass.getName());
// Convert parameters into map
- builder.addPropertyValue("parameters", convertParameters(serviceAnnotationAttributes.getStringArray("parameters")));
+ builder.addPropertyValue("parameters", convertParameters((String[]) serviceAnnotationAttributes.get("parameters")));
// Add methods parameters
List<MethodConfig> methodConfigs = convertMethodConfigs(serviceAnnotationAttributes.get("methods"));
if (!methodConfigs.isEmpty()) {
@@ -414,20 +415,20 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
}
// convert provider to providerIds
- String providerConfigId = serviceAnnotationAttributes.getString("provider");
+ String providerConfigId = (String) serviceAnnotationAttributes.get("provider");
if (StringUtils.hasText(providerConfigId)) {
addPropertyValue(builder, "providerIds", providerConfigId);
}
// Convert registry[] to registryIds
- String[] registryConfigIds = serviceAnnotationAttributes.getStringArray("registry");
+ String[] registryConfigIds = (String[]) serviceAnnotationAttributes.get("registry");
if (registryConfigIds != null && registryConfigIds.length > 0) {
resolveStringArray(registryConfigIds);
builder.addPropertyValue("registryIds", StringUtils.join(registryConfigIds, ','));
}
// Convert protocol[] to protocolIds
- String[] protocolConfigIds = serviceAnnotationAttributes.getStringArray("protocol");
+ String[] protocolConfigIds = (String[]) serviceAnnotationAttributes.get("protocol");
if (protocolConfigIds != null && protocolConfigIds.length > 0) {
resolveStringArray(protocolConfigIds);
builder.addPropertyValue("protocolIds", StringUtils.join(protocolConfigIds, ','));
@@ -435,19 +436,19 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
// TODO Could we ignore these attributes: applicatin/monitor/module ? Use global config
// monitor reference
- String monitorConfigId = serviceAnnotationAttributes.getString("monitor");
+ String monitorConfigId = (String) serviceAnnotationAttributes.get("monitor");
if (StringUtils.hasText(monitorConfigId)) {
addPropertyReference(builder, "monitor", monitorConfigId);
}
// application reference
- String applicationConfigId = serviceAnnotationAttributes.getString("application");
+ String applicationConfigId = (String) serviceAnnotationAttributes.get("application");
if (StringUtils.hasText(applicationConfigId)) {
addPropertyReference(builder, "application", applicationConfigId);
}
// module reference
- String moduleConfigId = serviceAnnotationAttributes.getString("module");
+ String moduleConfigId = (String) serviceAnnotationAttributes.get("module");
if (StringUtils.hasText(moduleConfigId)) {
addPropertyReference(builder, "module", moduleConfigId);
}
@@ -501,7 +502,99 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+ String[] beanNames = beanFactory.getBeanDefinitionNames();
+ for (String beanName : beanNames) {
+ BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
+ Map<String, Object> annotationAttributes = getServiceAnnotationAttributes(beanDefinition);
+ if (annotationAttributes != null) {
+ // process @DubboService at java-config @bean method
+ processAnnotatedBeanDefinition(beanName, (AnnotatedBeanDefinition) beanDefinition, annotationAttributes);
+ }
+ }
+ }
+
+ /**
+ * Get dubbo service annotation class at java-config @bean method
+ * @return return service annotation attributes map if found, or return null if not found.
+ */
+ private Map<String, Object> getServiceAnnotationAttributes(BeanDefinition beanDefinition) {
+ if (beanDefinition instanceof AnnotatedBeanDefinition) {
+ AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition;
+ MethodMetadata factoryMethodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata();
+ if (factoryMethodMetadata != null) {
+ // try all dubbo service annotation types
+ for (Class<? extends Annotation> annotationType : serviceAnnotationTypes) {
+ if (factoryMethodMetadata.isAnnotated(annotationType.getName())) {
+ // Since Spring 5.2
+ // return factoryMethodMetadata.getAnnotations().get(annotationType).filterDefaultValues().asMap();
+ // Compatible with Spring 4.x
+ Map<String, Object> annotationAttributes = factoryMethodMetadata.getAnnotationAttributes(annotationType.getName());
+ return filterDefaultValues(annotationType, annotationAttributes);
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * process @DubboService at java-config @bean method
+ * <pre class="code">
+ * @Configuration
+ * public class ProviderConfig {
+ *
+ * @Bean
+ * @DubboService(group="demo", version="1.2.3")
+ * public DemoService demoService() {
+ * return new DemoServiceImpl();
+ * }
+ *
+ * }
+ * </pre>
+ * @param refServiceBeanName
+ * @param refServiceBeanDefinition
+ * @param attributes
+ */
+ private void processAnnotatedBeanDefinition(String refServiceBeanName, AnnotatedBeanDefinition refServiceBeanDefinition, Map<String, Object> attributes) {
+
+ Map<String, Object> serviceAnnotationAttributes = new LinkedHashMap<>(attributes);
+
+ // get bean class from return type
+ String returnTypeName = refServiceBeanDefinition.getFactoryMethodMetadata().getReturnTypeName();
+ Class<?> beanClass = resolveClassName(returnTypeName, classLoader);
+
+ Class<?> interfaceClass = resolveServiceInterfaceClass(serviceAnnotationAttributes, beanClass);
+
+ // ServiceBean Bean name
+ String serviceBeanName = generateServiceBeanName(serviceAnnotationAttributes, interfaceClass);
+
+ AbstractBeanDefinition serviceBeanDefinition = buildServiceBeanDefinition(serviceAnnotationAttributes, interfaceClass, refServiceBeanName);
+
+ // set id
+ serviceBeanDefinition.getPropertyValues().add(Constants.ID, serviceBeanName);
+ registerServiceBeanDefinition(serviceBeanName, serviceBeanDefinition, interfaceClass);
+ }
+
+ private void registerServiceBeanDefinition(String serviceBeanName, AbstractBeanDefinition serviceBeanDefinition, Class<?> interfaceClass) {
+ // check service bean
+ if (registry.containsBeanDefinition(serviceBeanName)) {
+ BeanDefinition existingDefinition = registry.getBeanDefinition(serviceBeanName);
+ if (existingDefinition.equals(serviceBeanDefinition)) {
+ // exist equipment bean definition
+ return;
+ }
+
+ String msg = "Found duplicated BeanDefinition of service interface [" + interfaceClass.getName() + "] with bean name [" + serviceBeanName +
+ "], existing definition [ " + existingDefinition + "], new definition [" + serviceBeanDefinition + "]";
+ logger.error(msg);
+ throw new BeanDefinitionStoreException(serviceBeanDefinition.getResourceDescription(), serviceBeanName, msg);
+ }
+
+ registry.registerBeanDefinition(serviceBeanName, serviceBeanDefinition);
+ if (logger.isInfoEnabled()) {
+ logger.info("Register ServiceBean[" + serviceBeanName + "]: " + serviceBeanDefinition);
+ }
}
@Override
@@ -518,4 +611,28 @@ public class ServiceAnnotationPostProcessor implements BeanDefinitionRegistryPos
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ this.servicePackagesHolder = applicationContext.getBean(ServicePackagesHolder.class);
+ }
+
+ private class ScanExcludeFilter implements TypeFilter {
+
+ private int excludedCount;
+
+ @Override
+ public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
+ String className = metadataReader.getClassMetadata().getClassName();
+ boolean excluded = servicePackagesHolder.isClassScanned(className);
+ if (excluded) {
+ excludedCount ++;
+ }
+ return excluded;
+ }
+
+ public int getExcludedCount() {
+ return excludedCount;
+ }
+ }
}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServicePackagesHolder.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServicePackagesHolder.java
new file mode 100644
index 0000000..75eb6ca
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServicePackagesHolder.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.spring.beans.factory.annotation;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A temp holder for scanned packages of service.
+ */
+public class ServicePackagesHolder {
+
+ public static final String BEAN_NAME = "dubboServicePackagesHolder";
+
+ private final Set<String> scannedPackages = new HashSet<>();
+
+ private final Set<String> scannedClasses = new HashSet<>();
+
+
+ public void addScannedPackage(String apackage) {
+ apackage = normalizePackage(apackage);
+ synchronized (scannedPackages) {
+ scannedPackages.add(apackage);
+ }
+ }
+
+ public boolean isPackageScanned(String packageName) {
+ packageName = normalizePackage(packageName);
+ synchronized (scannedPackages) {
+ if (scannedPackages.contains(packageName)) {
+ return true;
+ }
+ for (String scannedPackage : scannedPackages) {
+ if (isSubPackage(packageName, scannedPackage)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public void addScannedClass(String className) {
+ synchronized (scannedClasses) {
+ scannedClasses.add(className);
+ }
+ }
+
+ public boolean isClassScanned(String className) {
+ synchronized (scannedClasses) {
+ return scannedClasses.contains(className);
+ }
+ }
+
+ /**
+ * Whether test package is sub package of parent package
+ * @param testPkg
+ * @param parent
+ * @return
+ */
+ private boolean isSubPackage(String testPkg, String parent) {
+ // child pkg startsWith parent pkg
+ return testPkg.startsWith(parent);
+ }
+
+ private String normalizePackage(String apackage) {
+ if (!apackage.endsWith(".")) {
+ apackage += ".";
+ }
+ return apackage;
+ }
+
+}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboInfraBeanRegisterPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboInfraBeanRegisterPostProcessor.java
index 7299ab6..6533fff 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboInfraBeanRegisterPostProcessor.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboInfraBeanRegisterPostProcessor.java
@@ -54,7 +54,7 @@ public class DubboInfraBeanRegisterPostProcessor implements BeanDefinitionRegist
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
DubboBeanUtils.registerBeansIfNotExists(registry);
- // register ConfigManager
+ // register ConfigManager singleton
beanFactory.registerSingleton(ConfigManager.BEAN_NAME, ApplicationModel.getConfigManager());
}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrar.java
index be57482..7807efe 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrar.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrar.java
@@ -53,12 +53,12 @@ public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistra
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
+ // @since 2.7.6 Register the common beans
+ registerCommonBeans(registry);
+
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
registerServiceAnnotationPostProcessor(packagesToScan, registry);
-
- // @since 2.7.6 Register the common beans
- registerCommonBeans(registry);
}
/**
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java
index abcca76..305cfd4 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java
@@ -29,10 +29,10 @@ import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.ProviderConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.spring.Constants;
import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.dubbo.config.spring.ServiceBean;
import org.springframework.beans.PropertyValue;
-import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
@@ -278,7 +278,7 @@ public class DubboBeanDefinitionParser implements BeanDefinitionParser {
beanDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, beanName+"_decorated"));
// signal object type since Spring 5.2
- beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, interfaceClass);
+ beanDefinition.setAttribute(Constants.OBJECT_TYPE_ATTRIBUTE, interfaceClass);
//mark property value as optional
List<PropertyValue> propertyValues = beanDefinition.getPropertyValues().getPropertyValueList();
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboAnnotationUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboAnnotationUtils.java
index 7cf3527..7fe662f 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboAnnotationUtils.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboAnnotationUtils.java
@@ -19,10 +19,11 @@ package org.apache.dubbo.config.spring.util;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
-import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
+import java.util.Map;
+
import static com.alibaba.spring.util.AnnotationUtils.getAttribute;
import static org.springframework.util.ClassUtils.getAllInterfacesForClass;
import static org.springframework.util.ClassUtils.resolveClassName;
@@ -59,14 +60,14 @@ public class DubboAnnotationUtils {
}
/**
- * Resolve the interface name from {@link AnnotationAttributes}
+ * Resolve the interface name from annotation attributes
*
- * @param attributes {@link AnnotationAttributes} instance, may be {@link Service @Service} or {@link Reference @Reference}
- * @param defaultInterfaceClass the default {@link Class class} of interface
+ * @param attributes annotation attributes instance, may be {@link Service @Service} or {@link Reference @Reference}
+ * @param defaultInterfaceClass the default class of interface
* @return the interface name if found
* @throws IllegalStateException if interface name was not found
*/
- public static String resolveInterfaceName(AnnotationAttributes attributes, Class<?> defaultInterfaceClass) {
+ public static String resolveInterfaceName(Map<String, Object> attributes, Class<?> defaultInterfaceClass) {
Boolean generic = getAttribute(attributes, "generic");
if (generic != null && generic) {
// it's a generic reference
@@ -79,22 +80,22 @@ public class DubboAnnotationUtils {
}
/**
- * Resolve the {@link Class class} of Dubbo Service interface from the specified
- * {@link AnnotationAttributes annotation attributes} and annotated {@link Class class}.
+ * Resolve the interface class of Dubbo Service annotation from the specified
+ * annotation attributes and annotated class.
*
- * @param attributes {@link AnnotationAttributes annotation attributes}
- * @param defaultInterfaceClass the annotated {@link Class class}.
- * @return the {@link Class class} of Dubbo Service interface
+ * @param attributes annotation attributes
+ * @param defaultInterfaceClass the annotated class.
+ * @return the class of Dubbo Service interface
* @throws IllegalArgumentException if can't resolved
*/
- public static Class<?> resolveServiceInterfaceClass(AnnotationAttributes attributes, Class<?> defaultInterfaceClass)
+ public static Class<?> resolveServiceInterfaceClass(Map<String, Object> attributes, Class<?> defaultInterfaceClass)
throws IllegalArgumentException {
ClassLoader classLoader = defaultInterfaceClass != null ? defaultInterfaceClass.getClassLoader() : Thread.currentThread().getContextClassLoader();
Class<?> interfaceClass = getAttribute(attributes, "interfaceClass");
- if (void.class.equals(interfaceClass)) { // default or set void.class for purpose.
+ if (interfaceClass == null || void.class.equals(interfaceClass)) { // default or set void.class for purpose.
interfaceClass = null;
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboBeanUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboBeanUtils.java
index d3ccfdf..126fa5e 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboBeanUtils.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboBeanUtils.java
@@ -18,6 +18,7 @@ package org.apache.dubbo.config.spring.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.dubbo.config.spring.beans.factory.annotation.ServicePackagesHolder;
import org.apache.dubbo.config.spring.context.DubboConfigInitializationPostProcessor;
import org.apache.dubbo.config.spring.reference.ReferenceBeanManager;
import org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigAliasPostProcessor;
@@ -58,12 +59,15 @@ public interface DubboBeanUtils {
*/
static void registerCommonBeans(BeanDefinitionRegistry registry) {
+ registerInfrastructureBean(registry, ServicePackagesHolder.BEAN_NAME, ServicePackagesHolder.class);
+
registerInfrastructureBean(registry, ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);
// Since 2.5.7 Register @Reference Annotation Bean Processor as an infrastructure Bean
registerInfrastructureBean(registry, ReferenceAnnotationBeanPostProcessor.BEAN_NAME,
ReferenceAnnotationBeanPostProcessor.class);
+ // TODO Whether DubboConfigAliasPostProcessor can be removed ?
// Since 2.7.4 [Feature] https://github.com/apache/dubbo/issues/5093
registerInfrastructureBean(registry, DubboConfigAliasPostProcessor.BEAN_NAME,
DubboConfigAliasPostProcessor.class);
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/JavaConfigBeanTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/JavaConfigBeanTest.java
index 97415e7..9e65281 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/JavaConfigBeanTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/JavaConfigBeanTest.java
@@ -22,10 +22,12 @@ import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.annotation.DubboReference;
+import org.apache.dubbo.config.annotation.DubboService;
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.config.spring.api.DemoService;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
+import org.apache.dubbo.config.spring.impl.DemoServiceImpl;
import org.apache.dubbo.rpc.Constants;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.junit.jupiter.api.AfterEach;
@@ -38,7 +40,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Collection;
-import java.util.HashMap;
import java.util.Map;
public class JavaConfigBeanTest {
@@ -70,15 +71,12 @@ public class JavaConfigBeanTest {
SysProps.setProperty("dubbo.protocol.port", "2346");
String registryAddress = "zookeeper://127.0.0.1:2181";
SysProps.setProperty("dubbo.registry.address", registryAddress);
+ SysProps.setProperty("dubbo.provider.group", "test");
- // test destroy flag
-// MockServiceDiscovery mockServiceDiscovery = (MockServiceDiscovery) ExtensionLoader.getExtensionLoader(ServiceDiscovery.class).getExtension("mock");
-// Assertions.assertEquals(false, mockServiceDiscovery.isDestroySucceed());
-
- AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
- TestConfiguration.class, ReferenceConfiguration.class);
+ AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(
+ TestConfiguration.class, ConsumerConfiguration.class, ProviderConfiguration.class);
try {
- applicationContext.start();
+ consumerContext.start();
ConfigManager configManager = ApplicationModel.getConfigManager();
ApplicationConfig application = configManager.getApplication().get();
@@ -101,7 +99,7 @@ public class JavaConfigBeanTest {
Assertions.assertEquals(false, consumerConfig.isCheck());
Assertions.assertEquals(2, consumerConfig.getRetries());
- Map<String, ReferenceBean> referenceBeanMap = applicationContext.getBeansOfType(ReferenceBean.class);
+ Map<String, ReferenceBean> referenceBeanMap = consumerContext.getBeansOfType(ReferenceBean.class);
Assertions.assertEquals(1, referenceBeanMap.size());
ReferenceBean referenceBean = referenceBeanMap.get("&demoService");
Assertions.assertNotNull(referenceBean);
@@ -112,13 +110,15 @@ public class JavaConfigBeanTest {
// consumer cannot override reference's attribute
Assertions.assertEquals(5, referenceConfig.getRetries());
+ DemoService referProxy = (DemoService) referenceConfig.get();
+ Assertions.assertTrue( referProxy instanceof DemoService);
+ String result = referProxy.sayName("dubbo");
+ Assertions.assertEquals("say:dubbo", result);
+
} finally {
- applicationContext.close();
+ consumerContext.close();
}
- // test destroy flag
- //Assertions.assertEquals(true, mockServiceDiscovery.isDestroySucceed());
-
}
@@ -160,7 +160,7 @@ public class JavaConfigBeanTest {
}
@Configuration
- static class ReferenceConfiguration {
+ static class ConsumerConfiguration {
@Bean
@DubboReference(scope = Constants.SCOPE_LOCAL, retries = 5)
@@ -169,4 +169,14 @@ public class JavaConfigBeanTest {
}
}
+
+ @Configuration
+ static class ProviderConfiguration {
+
+ @Bean
+ @DubboService(group = "demo")
+ public DemoService demoServiceImpl() {
+ return new DemoServiceImpl();
+ }
+ }
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationPostProcessorTest.java
index fa4aa80..78fa75f 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationPostProcessorTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationPostProcessorTest.java
@@ -19,6 +19,7 @@ package org.apache.dubbo.config.spring.beans.factory.annotation;
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
import org.apache.dubbo.config.spring.ServiceBean;
import org.apache.dubbo.config.spring.api.HelloService;
+import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
@@ -45,7 +46,8 @@ import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER
@ContextConfiguration(
classes = {
ServiceAnnotationTestConfiguration.class,
- ServiceAnnotationPostProcessorTest.class
+ ServiceAnnotationPostProcessorTest.class,
+ ServiceAnnotationPostProcessorTest.DuplicatedScanConfig.class
})
@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)
@TestPropertySource(properties = {
@@ -81,7 +83,7 @@ public class ServiceAnnotationPostProcessorTest {
Map<String, ServiceAnnotationPostProcessor> beanPostProcessorsMap =
beanFactory.getBeansOfType(ServiceAnnotationPostProcessor.class);
- Assertions.assertEquals(1, beanPostProcessorsMap.size());
+ Assertions.assertEquals(2, beanPostProcessorsMap.size());
}
@@ -98,4 +100,9 @@ public class ServiceAnnotationPostProcessorTest {
}
+ @DubboComponentScan({"org.apache.dubbo.config.spring.context.annotation", "${provider.package}"})
+ static class DuplicatedScanConfig {
+
+ }
+
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/extension/SpringExtensionFactoryTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/extension/SpringExtensionFactoryTest.java
index 6715a7b..ca70f1f 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/extension/SpringExtensionFactoryTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/extension/SpringExtensionFactoryTest.java
@@ -18,6 +18,7 @@ package org.apache.dubbo.config.spring.extension;
import org.apache.dubbo.common.extension.ExtensionFactory;
import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
import org.apache.dubbo.config.spring.api.DemoService;
import org.apache.dubbo.config.spring.api.HelloService;
import org.apache.dubbo.config.spring.impl.DemoServiceImpl;
@@ -41,6 +42,8 @@ public class SpringExtensionFactoryTest {
@BeforeEach
public void init() {
+ DubboBootstrap.reset();
+
// init SpringExtensionFactory
ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getExtension("spring");
@@ -56,6 +59,13 @@ public class SpringExtensionFactoryTest {
SpringExtensionFactory.addApplicationContext(context2);
}
+ @AfterEach
+ public void destroy() {
+ context1.close();
+ context2.close();
+ SpringExtensionFactory.clearContexts();
+ }
+
@Test
public void testGetExtensionBySPI() {
Protocol protocol = springExtensionFactory.getExtension(Protocol.class, "protocol");
@@ -70,13 +80,6 @@ public class SpringExtensionFactoryTest {
Assertions.assertNotNull(hello);
}
- @AfterEach
- public void destroy() {
- SpringExtensionFactory.clearContexts();
- context1.close();
- context2.close();
- }
-
@Bean("bean1")
public DemoService bean1() {
return new DemoServiceImpl();
diff --git a/dubbo-dependencies-bom/pom.xml b/dubbo-dependencies-bom/pom.xml
index 1831a11..e281b08 100644
--- a/dubbo-dependencies-bom/pom.xml
+++ b/dubbo-dependencies-bom/pom.xml
@@ -89,6 +89,7 @@
<properties>
<!-- Common libs -->
+ <!-- <spring_version>4.3.30.RELEASE</spring_version> -->
<spring_version>5.2.8.RELEASE</spring_version>
<javassist_version>3.23.1-GA</javassist_version>
<eclipse_collections_version>10.4.0</eclipse_collections_version>
diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/AbstractRequestAnnotationParameterProcessor.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/AbstractRequestAnnotationParameterProcessor.java
index 74807ea..2eac157 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/AbstractRequestAnnotationParameterProcessor.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/rest/springmvc/AbstractRequestAnnotationParameterProcessor.java
@@ -62,7 +62,7 @@ public abstract class AbstractRequestAnnotationParameterProcessor extends Abstra
private boolean isDefaultValue(Annotation annotation, String attributeName, Object attributeValue) {
String defaultValue = AnnotationUtils.getDefaultValue(annotation, attributeName);
- return Objects.equals(attributeValue, defaultValue);
+ return Objects.deepEquals(attributeValue, defaultValue);
}
protected boolean isEmpty(String str) {
diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboAutoConfiguration.java b/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboAutoConfiguration.java
index 4fb850c..51be6ac 100644
--- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboAutoConfiguration.java
+++ b/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboAutoConfiguration.java
@@ -31,7 +31,6 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
@@ -71,7 +70,6 @@ public class DubboAutoConfiguration implements ApplicationContextAware, BeanDefi
*/
@ConditionalOnProperty(prefix = DUBBO_SCAN_PREFIX, name = BASE_PACKAGES_PROPERTY_NAME)
@ConditionalOnBean(name = BASE_PACKAGES_BEAN_NAME)
- @ConditionalOnMissingBean
@Bean
public ServiceAnnotationPostProcessor serviceAnnotationBeanProcessor(@Qualifier(BASE_PACKAGES_BEAN_NAME)
Set<String> packagesToScan) {