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>
+ * &#64;Configuration
+ * class ProviderConfiguration {
+ *
+ *     &#64;Bean
+ *     &#64;DubboService(group="demo")
+ *     public DemoService demoServiceImpl() {
+ *         return new DemoServiceImpl();
+ *     }
+ * }
+ * </pre>
+ *
+ * <b>2. Using on implementation class of service:  </b>
+ * <pre>
+ * &#64;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 &lt;dubbbo:annotation /&gt;
+ * 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 &lt;dubbbo:annotation /&gt;
+ *
  *
  * @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">
+     * &#064;Configuration
+     * public class ProviderConfig {
+     *
+     *      &#064;Bean
+     *      &#064;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) {