You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2021/07/08 14:04:56 UTC

[dubbo] branch 3.0 updated: [3.0] Improve property placeholder resolving of reference bean (#8187)

This is an automated email from the ASF dual-hosted git repository.

albumenj 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 b260d45  [3.0] Improve property placeholder resolving of reference bean (#8187)
b260d45 is described below

commit b260d45a69354ebba5c112ce7a54b2f58ffef75a
Author: Gong Dewei <ky...@qq.com>
AuthorDate: Thu Jul 8 22:04:43 2021 +0800

    [3.0] Improve property placeholder resolving of reference bean (#8187)
    
    * Improve property placeholder resolving of config bean
    
    * Fix tests
    
    * register ReferenceAnnotationBeanPostProcessor as BeanPostProcessor early, improve reference key and reference name mapping
    
    * get ReferenceAnnotationBeanPostProcessor from beanFactory, fix tests
    
    * polish code
    
    * Improve tests
---
 .../dubbo/config/bootstrap/DubboBootstrap.java     |   1 +
 .../ReferenceAnnotationBeanPostProcessor.java      |  73 +++++-----
 .../DubboInfraBeanRegisterPostProcessor.java       |  13 +-
 .../spring/reference/ReferenceBeanManager.java     |  51 ++++---
 .../spring/reference/ReferenceBeanSupport.java     |  37 ++---
 .../dubbo/config/spring/util/DubboBeanUtils.java   |  52 +++----
 .../ReferenceAnnotationBeanPostProcessorTest.java  |  29 ++--
 .../SpringBootMultipleConfigPropsTest.java         |   2 +
 .../consumer/PropertyConfigurerTest.java           |   3 +-
 .../consumer2/PropertySourcesConfigurerTest.java   |   4 +-
 .../consumer3/PropertySourcesInJavaConfigTest.java | 160 +++++++++++++++++++++
 .../propertyconfigurer/consumer3/app.properties    |   4 +
 .../consumer3/dubbo-consumer.xml                   |  36 +++++
 .../config/spring/reference/ReferenceKeyTest.java  |  17 ++-
 .../LocalCallMultipleReferenceAnnotationsTest.java |   9 +-
 .../DubboRelaxedBinding2AutoConfigurationTest.java |  12 +-
 .../endpoint/metadata/AbstractDubboMetadata.java   |   4 +-
 .../CompatibleDubboAutoConfigurationTest.java      |   7 +-
 ...ubboAutoConfigurationTestWithoutProperties.java |   6 +-
 19 files changed, 386 insertions(+), 134 deletions(-)

diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java
index 5fe0196..9b0f063 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java
@@ -1528,6 +1528,7 @@ public class DubboBootstrap {
 
     private void destroyMetadataReports() {
         AbstractMetadataReportFactory.destroy();
+        MetadataReportInstance.reset();
         ExtensionLoader.resetExtensionLoader(MetadataReportFactory.class);
     }
 
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 0c4d8b4..5b2df1c 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
@@ -150,10 +150,14 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
                 } catch (BeansException e) {
                     throw e;
                 } catch (Exception e) {
-                    throw new RuntimeException("Prepare dubbo reference injection element failed", e);
+                    throw new IllegalStateException("Prepare dubbo reference injection element failed", e);
                 }
             }
         }
+
+        // This bean has bean register as BeanPostProcessor at org.apache.dubbo.config.spring.context.DubboInfraBeanRegisterPostProcessor.postProcessBeanFactory()
+        // so destroy this bean here, prevent register it as BeanPostProcessor again, avoid cause BeanPostProcessorChecker detection error
+        beanDefinitionRegistry.removeBeanDefinition(BEAN_NAME);
     }
 
     /**
@@ -273,18 +277,13 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
                 try {
                     prepareInjection(metadata);
                 } catch (Exception e) {
-                    throw new RuntimeException("Prepare dubbo reference injection element failed", e);
+                    throw new IllegalStateException("Prepare dubbo reference injection element failed", e);
                 }
             }
         }
     }
 
     @Override
-    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
-        return super.postProcessBeforeInitialization(bean, beanName);
-    }
-
-    @Override
     public PropertyValues postProcessPropertyValues(
             PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
 
@@ -362,12 +361,20 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
         }
 
         // check reference key
-        String referenceKey = ReferenceBeanSupport.generateReferenceKey(attributes, applicationContext.getEnvironment());
+        String referenceKey = ReferenceBeanSupport.generateReferenceKey(attributes, applicationContext);
 
-        // check registered reference beans in referenceBeanManager
-        List<String> registeredReferenceBeanNames = referenceBeanManager.getByKey(referenceKey);
-        if (registeredReferenceBeanNames.contains(referenceBeanName)) {
-            return referenceBeanName;
+        // find reference bean name by reference key
+        List<String> registeredReferenceBeanNames = referenceBeanManager.getBeanNamesByKey(referenceKey);
+        if (registeredReferenceBeanNames.size() > 0) {
+            // found same name and reference key
+            if (registeredReferenceBeanNames.contains(referenceBeanName)) {
+                return referenceBeanName;
+            }
+//            else if (renameable) {
+//                // reference key matched, but difference bean name
+//                return registeredReferenceBeanNames.get(0);
+//            }
+            // specify bean name by id attribute, it will register alias later
         }
 
         //check bean definition
@@ -379,7 +386,7 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
 
             if (isReferenceBean(prevBeanDefinition)) {
                 //check reference key
-                String prevReferenceKey = ReferenceBeanSupport.generateReferenceKey(prevBeanDefinition, applicationContext.getEnvironment());
+                String prevReferenceKey = ReferenceBeanSupport.generateReferenceKey(prevBeanDefinition, applicationContext);
                 if (StringUtils.isEquals(prevReferenceKey, referenceKey)) {
                     //found matched dubbo reference bean, ignore register
                     return referenceBeanName;
@@ -389,27 +396,23 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
                 Assert.notNull(prevBeanDefinition, "The interface class of ReferenceBean is not initialized");
                 prevBeanType = prevInterfaceClass.getName();
                 prevBeanDesc = referenceBeanName + "[" + prevReferenceKey + "]";
+
                 //check bean type
-                if (StringUtils.isEquals(prevBeanType, interfaceName)) {
-                    throw new BeanCreationException("Already exists another reference bean with the same bean name and type but difference attributes. " +
-                            "In order to avoid injection confusion, please modify the name of one of the beans: " +
-                            "prev: " + prevBeanDesc + ", new: " + newBeanDesc+". "+checkLocation);
-                }
-            } else {
-                //check bean type
-                if (StringUtils.isEquals(prevBeanType, interfaceName)) {
-                    throw new BeanCreationException("Already exists another bean definition with the same bean name and type. " +
-                            "In order to avoid injection confusion, please modify the name of one of the beans: " +
-                            "prev: " + prevBeanDesc + ", new: " + newBeanDesc+". "+checkLocation);
-                }
+                // If two reference beans are the same type and name, then other class injection them by type or name are confusion.
+                // Let it go, Spring find candidate bean will check it
+//                if (StringUtils.isEquals(prevBeanType, interfaceName)) {
+//                    throw new BeanCreationException("Already exists another reference bean with the same bean name and type but difference attributes. " +
+//                        "In order to avoid injection confusion later, please modify the name of one of the beans: " +
+//                        "prev: " + prevBeanDesc + ", new: " + newBeanDesc+". "+checkLocation);
+//                }
             }
 
             // bean name from attribute 'id' or java-config bean, cannot be renamed
             if (!renameable) {
-                throw new BeanCreationException("Already exists another bean definition with the same bean name, " +
-                        "but cannot rename the reference bean name (specify the id attribute or java-config bean), " +
-                        "please modify the name of one of the beans: " +
-                        "prev: " + prevBeanDesc + ", new: " + newBeanDesc+". "+checkLocation);
+                throw new BeanCreationException("Already exists another bean definition with the same bean name [" + referenceBeanName + "], " +
+                    "but cannot rename the reference bean name (specify the id attribute or java-config bean), " +
+                    "please modify the name of one of the beans: " +
+                    "prev: " + prevBeanDesc + ", new: " + newBeanDesc + ". " + checkLocation);
             }
 
             // the prev bean type is different, rename the new reference bean
@@ -421,17 +424,18 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
             }
             newBeanDesc = newReferenceBeanName + "[" + referenceKey + "]";
 
-            logger.warn("Already exists another bean definition with the same bean name but difference type, " +
-                    "rename dubbo reference bean to: " + newReferenceBeanName + ". " +
-                    "It is recommended to modify the name of one of the beans to avoid injection problems. " +
-                    "prev: " + prevBeanDesc + ", new: " + newBeanDesc+". "+checkLocation);
+            logger.warn("Already exists another bean definition with the same bean name [" + referenceBeanName + "], " +
+                "rename dubbo reference bean to [" + newReferenceBeanName + "]. " +
+                "It is recommended to modify the name of one of the beans to avoid injection problems. " +
+                "prev: " + prevBeanDesc + ", new: " + newBeanDesc + ". " + checkLocation);
             referenceBeanName = newReferenceBeanName;
         }
         attributes.put(ReferenceAttributes.ID, referenceBeanName);
 
-        // If registered matched reference before, add alias
+        // If registered matched reference before, just register alias
         if (registeredReferenceBeanNames.size() > 0) {
             beanDefinitionRegistry.registerAlias(registeredReferenceBeanNames.get(0), referenceBeanName);
+            referenceBeanManager.registerReferenceKeyAndBeanName(referenceKey, referenceBeanName);
             return referenceBeanName;
         }
 
@@ -460,6 +464,7 @@ public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBean
         beanDefinition.setAttribute(Constants.OBJECT_TYPE_ATTRIBUTE, interfaceClass);
 
         beanDefinitionRegistry.registerBeanDefinition(referenceBeanName, beanDefinition);
+        referenceBeanManager.registerReferenceKeyAndBeanName(referenceKey, referenceBeanName);
         logger.info("Register dubbo reference bean: "+referenceBeanName+" = "+referenceKey+" at "+member);
         return referenceBeanName;
     }
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 927317e..a16bd30 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
@@ -37,7 +37,8 @@ import java.util.SortedMap;
  * Register some infrastructure beans if not exists.
  * This post-processor MUST impl BeanDefinitionRegistryPostProcessor,
  * in order to enable the registered BeanFactoryPostProcessor bean to be loaded and executed.
- * @see org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List)
+ * @see org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(
+ * org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List)
  */
 public class DubboInfraBeanRegisterPostProcessor implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
 
@@ -56,7 +57,15 @@ public class DubboInfraBeanRegisterPostProcessor implements BeanDefinitionRegist
 
     @Override
     public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
-        DubboBeanUtils.registerBeansIfNotExists(registry);
+
+        // register ReferenceAnnotationBeanPostProcessor early before PropertySourcesPlaceholderConfigurer/PropertyPlaceholderConfigurer
+        // for processing early init ReferenceBean
+        ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor = beanFactory.getBean(
+            ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);
+        beanFactory.addBeanPostProcessor(referenceAnnotationBeanPostProcessor);
+
+        // register PropertySourcesPlaceholderConfigurer bean if not exits
+        DubboBeanUtils.registerBeansIfNotExists(beanFactory, registry);
 
         // 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/reference/ReferenceBeanManager.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/reference/ReferenceBeanManager.java
index 73b9e91..e5b04aa 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/reference/ReferenceBeanManager.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/reference/ReferenceBeanManager.java
@@ -25,11 +25,11 @@ import org.apache.dubbo.config.spring.ReferenceBean;
 import org.springframework.beans.BeansException;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
-import org.springframework.core.env.PropertyResolver;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -38,40 +38,44 @@ import java.util.concurrent.ConcurrentHashMap;
 public class ReferenceBeanManager implements ApplicationContextAware {
     public static final String BEAN_NAME = "dubboReferenceBeanManager";
     private final Log logger = LogFactory.getLog(getClass());
-    //reference bean id/name -> ReferenceBean
-    private Map<String, ReferenceBean> referenceIdMap = new ConcurrentHashMap<>();
 
-    //reference key -> [ reference bean names ]
+    //reference key -> reference bean names
     private Map<String, List<String>> referenceKeyMap = new ConcurrentHashMap<>();
 
+    // reference alias -> reference bean name
+    private Map<String, String> referenceAliasMap = new ConcurrentHashMap<>();
+
+    //reference bean name -> ReferenceBean
+    private Map<String, ReferenceBean> referenceBeanMap = new ConcurrentHashMap<>();
+
     //reference key -> ReferenceConfig instance
     private Map<String, ReferenceConfig> referenceConfigMap = new ConcurrentHashMap<>();
+
     private ApplicationContext applicationContext;
     private volatile boolean initialized = false;
 
     public void addReference(ReferenceBean referenceBean) throws Exception {
         String referenceBeanName = referenceBean.getId();
         Assert.notEmptyString(referenceBeanName, "The id of ReferenceBean cannot be empty");
-        PropertyResolver propertyResolver = applicationContext.getEnvironment();
 
         if (!initialized) {
             //TODO add issue url to describe early initialization
             logger.warn("Early initialize reference bean before DubboConfigInitializationPostProcessor," +
                     " the BeanPostProcessor has not been loaded at this time, which may cause abnormalities in some components (such as seata): " +
-                    referenceBeanName + " = " + ReferenceBeanSupport.generateReferenceKey(referenceBean, propertyResolver));
+                    referenceBeanName + " = " + ReferenceBeanSupport.generateReferenceKey(referenceBean, applicationContext));
         }
 
-        String referenceKey = ReferenceBeanSupport.generateReferenceKey(referenceBean, propertyResolver);
-        ReferenceBean oldReferenceBean = referenceIdMap.get(referenceBeanName);
+        String referenceKey = ReferenceBeanSupport.generateReferenceKey(referenceBean, applicationContext);
+        ReferenceBean oldReferenceBean = referenceBeanMap.get(referenceBeanName);
         if (oldReferenceBean != null) {
             if (referenceBean != oldReferenceBean) {
-                String oldReferenceKey = ReferenceBeanSupport.generateReferenceKey(oldReferenceBean, propertyResolver);
+                String oldReferenceKey = ReferenceBeanSupport.generateReferenceKey(oldReferenceBean, applicationContext);
                 throw new IllegalStateException("Found duplicated ReferenceBean with id: " + referenceBeanName +
                         ", old: " + oldReferenceKey + ", new: " + referenceKey);
             }
             return;
         }
-        referenceIdMap.put(referenceBeanName, referenceBean);
+        referenceBeanMap.put(referenceBeanName, referenceBean);
         //save cache, map reference key to referenceBeanName
         this.registerReferenceKeyAndBeanName(referenceKey, referenceBeanName);
 
@@ -81,20 +85,31 @@ public class ReferenceBeanManager implements ApplicationContextAware {
         }
     }
 
-    public void registerReferenceKeyAndBeanName(String referenceKey, String referenceBeanName) {
-        referenceKeyMap.getOrDefault(referenceKey, new ArrayList<>()).add(referenceBeanName);
+    public void registerReferenceKeyAndBeanName(String referenceKey, String referenceBeanNameOrAlias) {
+        List<String> list = referenceKeyMap.computeIfAbsent(referenceKey, (key) -> new ArrayList<>());
+        if (!list.contains(referenceBeanNameOrAlias)) {
+            list.add(referenceBeanNameOrAlias);
+            // register bean name as alias
+            referenceAliasMap.put(referenceBeanNameOrAlias, list.get(0));
+        }
+    }
+
+    public ReferenceBean getById(String referenceBeanNameOrAlias) {
+        String referenceBeanName = transformName(referenceBeanNameOrAlias);
+        return referenceBeanMap.get(referenceBeanName);
     }
 
-    public ReferenceBean getById(String key) {
-        return referenceIdMap.get(key);
+    // convert reference name/alias to referenceBeanName
+    private String transformName(String referenceBeanNameOrAlias) {
+        return referenceAliasMap.getOrDefault(referenceBeanNameOrAlias, referenceBeanNameOrAlias);
     }
 
-    public List<String> getByKey(String key) {
-        return Collections.unmodifiableList(referenceKeyMap.getOrDefault(key, new ArrayList<>()));
+    public List<String> getBeanNamesByKey(String key) {
+        return Collections.unmodifiableList(referenceKeyMap.getOrDefault(key, Collections.EMPTY_LIST));
     }
 
     public Collection<ReferenceBean> getReferences() {
-        return referenceIdMap.values();
+        return new HashSet<>(referenceBeanMap.values());
     }
 
     @Override
@@ -135,7 +150,7 @@ public class ReferenceBeanManager implements ApplicationContextAware {
         // TOTO check same unique service name but difference reference key (means difference attributes).
 
         // reference key
-        String referenceKey = ReferenceBeanSupport.generateReferenceKey(referenceBean, applicationContext.getEnvironment());
+        String referenceKey = ReferenceBeanSupport.generateReferenceKey(referenceBean, applicationContext);
 
         ReferenceConfig referenceConfig = referenceConfigMap.get(referenceKey);
         if (referenceConfig == null) {
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/reference/ReferenceBeanSupport.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/reference/ReferenceBeanSupport.java
index 3ba683b..678b5db 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/reference/ReferenceBeanSupport.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/reference/ReferenceBeanSupport.java
@@ -28,10 +28,11 @@ import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.beans.factory.config.BeanDefinitionHolder;
 import org.springframework.beans.factory.config.RuntimeBeanReference;
 import org.springframework.beans.factory.config.TypedStringValue;
+import org.springframework.beans.factory.support.AbstractBeanFactory;
 import org.springframework.beans.factory.support.ManagedList;
 import org.springframework.beans.factory.support.ManagedMap;
+import org.springframework.context.ApplicationContext;
 import org.springframework.core.annotation.AnnotationAttributes;
-import org.springframework.core.env.PropertyResolver;
 import org.springframework.util.ObjectUtils;
 
 import java.lang.annotation.Annotation;
@@ -70,7 +71,8 @@ public class ReferenceBeanSupport {
 
         //reset generic value
         String generic = String.valueOf(defaultInterfaceClass == GenericService.class);
-        String oldGeneric = attributes.containsValue(ReferenceAttributes.GENERIC) ? String.valueOf(attributes.get(ReferenceAttributes.GENERIC)) : "false";
+        String oldGeneric = attributes.containsValue(ReferenceAttributes.GENERIC) ?
+            String.valueOf(attributes.get(ReferenceAttributes.GENERIC)) : "false";
         if (!StringUtils.isEquals(oldGeneric, generic)) {
             attributes.put(ReferenceAttributes.GENERIC, generic);
         }
@@ -86,7 +88,7 @@ public class ReferenceBeanSupport {
 
     }
 
-    public static String generateReferenceKey(Map<String, Object> attributes, PropertyResolver propertyResolver) {
+    public static String generateReferenceKey(Map<String, Object> attributes, ApplicationContext applicationContext) {
 
         String interfaceClass = (String) attributes.get(ReferenceAttributes.INTERFACE);
         Assert.notEmptyString(interfaceClass, "No interface class or name found from attributes");
@@ -108,7 +110,9 @@ public class ReferenceBeanSupport {
         //sort attributes keys
         List<String> sortedAttrKeys = new ArrayList<>(attributes.keySet());
         Collections.sort(sortedAttrKeys);
-        List<String> ignoredAttrs = Arrays.asList(ReferenceAttributes.ID, ReferenceAttributes.GROUP, ReferenceAttributes.VERSION, ReferenceAttributes.INTERFACE, ReferenceAttributes.INTERFACE_NAME, ReferenceAttributes.INTERFACE_CLASS);
+        List<String> ignoredAttrs = Arrays.asList(ReferenceAttributes.ID, ReferenceAttributes.GROUP,
+            ReferenceAttributes.VERSION, ReferenceAttributes.INTERFACE, ReferenceAttributes.INTERFACE_NAME,
+            ReferenceAttributes.INTERFACE_CLASS);
         for (String key : sortedAttrKeys) {
             if (ignoredAttrs.contains(key)) {
                 continue;
@@ -130,18 +134,19 @@ public class ReferenceBeanSupport {
         }
 
         String referenceKey = beanNameBuilder.toString();
-        if (propertyResolver != null) {
-            referenceKey = propertyResolver.resolveRequiredPlaceholders(referenceKey);
+        if (applicationContext != null) {
+            // resolve placeholder with Spring Environment
+            referenceKey = applicationContext.getEnvironment().resolvePlaceholders(referenceKey);
+            // resolve placeholder with Spring BeanFactory ( using PropertyResourceConfigurer/PropertySourcesPlaceholderConfigurer )
+            referenceKey = ((AbstractBeanFactory) applicationContext.getAutowireCapableBeanFactory()).resolveEmbeddedValue(referenceKey);
         }
+        // The property placeholder maybe not resolved if is early init
+        // if (referenceKey != null && referenceKey.contains("${")) {
+        //     throw new IllegalStateException("Reference key contains unresolved placeholders ${..} : " + referenceKey);
+        // }
         return referenceKey;
     }
 
-//    public static void verifyReferenceKey(String referenceKey) {
-//        if (referenceKey != null && referenceKey.contains("${")) {
-//            throw new IllegalStateException("Reference key contains unresolved placeholders ${..}");
-//        }
-//    }
-
     private static String convertToString(String key, Object obj) {
         if (obj == null) {
             return null;
@@ -226,12 +231,12 @@ public class ReferenceBeanSupport {
         return map;
     }
 
-    public static String generateReferenceKey(ReferenceBean referenceBean, PropertyResolver propertyResolver) {
-        return generateReferenceKey(getReferenceAttributes(referenceBean), propertyResolver);
+    public static String generateReferenceKey(ReferenceBean referenceBean, ApplicationContext applicationContext) {
+        return generateReferenceKey(getReferenceAttributes(referenceBean), applicationContext);
     }
 
-    public static String generateReferenceKey(BeanDefinition beanDefinition, PropertyResolver propertyResolver) {
-        return generateReferenceKey(getReferenceAttributes(beanDefinition), propertyResolver);
+    public static String generateReferenceKey(BeanDefinition beanDefinition, ApplicationContext applicationContext) {
+        return generateReferenceKey(getReferenceAttributes(beanDefinition), applicationContext);
     }
 
     public static Map<String, Object> getReferenceAttributes(ReferenceBean referenceBean) {
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 126fa5e..b5a1a0c 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
@@ -28,15 +28,17 @@ import org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener;
 import org.apache.dubbo.config.spring.context.DubboInfraBeanRegisterPostProcessor;
 import org.apache.dubbo.config.spring.context.DubboLifecycleComponentApplicationListener;
 import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.AbstractBeanFactory;
 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
 import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.context.ApplicationContext;
 import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
 
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Objects;
 
 /**
  * Dubbo Bean utilities class
@@ -126,33 +128,27 @@ public interface DubboBeanUtils {
      * in order to enable the registered BeanFactoryPostProcessor bean to be loaded and executed.
      * @see DubboInfraBeanRegisterPostProcessor
      * @see org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List)
+     * @param beanFactory
      * @param registry
      */
-    static void registerBeansIfNotExists(BeanDefinitionRegistry registry) {
-        // Resolve ${...} placeholders of bean definition with Spring Environment
-
-        // If PropertyPlaceholderConfigurer already exists, PropertySourcesPlaceholderConfigurer cannot be registered.
-        // When both of them exist, a conflict will occur, and an exception will be thrown when encountering an unresolved placeholder
-
-        if (!checkBeanExists(registry, PropertyPlaceholderConfigurer.class)) {
+    static void registerBeansIfNotExists(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry) {
+        // Auto register a PropertyPlaceholderConfigurer bean to resolve placeholders with Spring Environment PropertySources
+        // when loading dubbo xml config with @ImportResource
+        if (!checkBeanExists(beanFactory, PropertySourcesPlaceholderConfigurer.class)) {
             Map<String, Object> propertySourcesPlaceholderPropertyValues = new HashMap<>();
-            // to make sure the default PropertySourcesPlaceholderConfigurer's priority is higher than PropertyPlaceholderConfigurer
-            propertySourcesPlaceholderPropertyValues.put("order", 0);
-            registerBeanDefinitionIfNotExists(registry, PropertySourcesPlaceholderConfigurer.class.getName(),
+            propertySourcesPlaceholderPropertyValues.put("ignoreUnresolvablePlaceholders", true);
+
+            registerBeanDefinition(registry, PropertySourcesPlaceholderConfigurer.class.getName(),
                     PropertySourcesPlaceholderConfigurer.class, propertySourcesPlaceholderPropertyValues);
         }
     }
 
-    static boolean registerBeanDefinitionIfNotExists(BeanDefinitionRegistry registry, String beanName,
+    static boolean registerBeanDefinition(BeanDefinitionRegistry registry, String beanName,
                                                      Class<?> beanClass, Map<String, Object> extraPropertyValues) {
         if (registry.containsBeanDefinition(beanName)) {
             return false;
         }
 
-        if (checkBeanExists(registry, beanClass)) {
-            return false;
-        }
-
         BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(beanClass).getBeanDefinition();
         if (extraPropertyValues != null) {
             for (Map.Entry<String, Object> entry : extraPropertyValues.entrySet()) {
@@ -161,19 +157,25 @@ public interface DubboBeanUtils {
         }
 
         registry.registerBeanDefinition(beanName, beanDefinition);
-
         return true;
     }
 
-    static boolean checkBeanExists(BeanDefinitionRegistry registry, Class<?> beanClass) {
-        String[] candidates = registry.getBeanDefinitionNames();
-        for (String candidate : candidates) {
-            BeanDefinition beanDefinition = registry.getBeanDefinition(candidate);
-            if (Objects.equals(beanDefinition.getBeanClassName(), beanClass.getName())) {
-                return true;
+    static boolean checkBeanExists(ConfigurableListableBeanFactory beanFactory, Class<?> targetClass) {
+        String[] beanNames = beanFactory.getBeanNamesForType(targetClass, true, false);
+        return (beanNames != null && beanNames.length > 0);
+    }
+
+
+    static ReferenceAnnotationBeanPostProcessor getReferenceAnnotationBeanPostProcessor(AbstractBeanFactory beanFactory) {
+        for (BeanPostProcessor beanPostProcessor : beanFactory.getBeanPostProcessors()) {
+            if (beanPostProcessor instanceof ReferenceAnnotationBeanPostProcessor) {
+                return (ReferenceAnnotationBeanPostProcessor) beanPostProcessor;
             }
         }
-        return false;
+        return null;
     }
 
+    static ReferenceAnnotationBeanPostProcessor getReferenceAnnotationBeanPostProcessor(ApplicationContext applicationContext) {
+        return getReferenceAnnotationBeanPostProcessor((AbstractBeanFactory) applicationContext.getAutowireCapableBeanFactory());
+    }
 }
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
index ec301e6..8a040af 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
@@ -27,7 +27,7 @@ import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
 import org.apache.dubbo.config.spring.reference.ReferenceBeanManager;
 import org.apache.dubbo.config.spring.api.DemoService;
 import org.apache.dubbo.config.spring.api.HelloService;
-import org.apache.dubbo.config.utils.ReferenceConfigCache;
+import org.apache.dubbo.config.spring.util.DubboBeanUtils;
 import org.apache.dubbo.rpc.RpcContext;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.annotation.Around;
@@ -54,7 +54,6 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
-import static org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor.BEAN_NAME;
 import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD;
 
 /**
@@ -141,11 +140,12 @@ public class ReferenceAnnotationBeanPostProcessorTest {
         Assertions.assertNotNull(testBean.getDemoServiceFromParent());
         Assertions.assertNotNull(testBean.getDemoService());
         Assertions.assertNotNull(testBean.myDemoService);
-        Assertions.assertEquals(4, demoServicesMap.size());
-        Assertions.assertNotNull(demoServicesMap.get("demoServiceImpl"));
-        Assertions.assertNotNull(demoServicesMap.get("myDemoService"));
-        Assertions.assertNotNull(demoServicesMap.get("demoService"));
-        Assertions.assertNotNull(demoServicesMap.get("demoServiceFromParent"));
+        Assertions.assertEquals(2, demoServicesMap.size());
+
+        Assertions.assertNotNull(context.getBean("demoServiceImpl"));
+        Assertions.assertNotNull(context.getBean("myDemoService"));
+        Assertions.assertNotNull(context.getBean("demoService"));
+        Assertions.assertNotNull(context.getBean("demoServiceFromParent"));
 
         String callSuffix = AOP_SUFFIX + " from "+ NetUtils.getLocalHost() +":12345";
         String localCallSuffix = AOP_SUFFIX + " from 127.0.0.1:0";
@@ -174,8 +174,7 @@ public class ReferenceAnnotationBeanPostProcessorTest {
     @Test
     public void testGetInjectedFieldReferenceBeanMap() {
 
-        ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME,
-                ReferenceAnnotationBeanPostProcessor.class);
+        ReferenceAnnotationBeanPostProcessor beanPostProcessor = getReferenceAnnotationBeanPostProcessor();
 
         Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> referenceBeanMap =
                 beanPostProcessor.getInjectedFieldReferenceBeanMap();
@@ -201,11 +200,14 @@ public class ReferenceAnnotationBeanPostProcessorTest {
         }
     }
 
+    private ReferenceAnnotationBeanPostProcessor getReferenceAnnotationBeanPostProcessor() {
+        return DubboBeanUtils.getReferenceAnnotationBeanPostProcessor(context);
+    }
+
     @Test
     public void testGetInjectedMethodReferenceBeanMap() {
 
-        ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME,
-                ReferenceAnnotationBeanPostProcessor.class);
+        ReferenceAnnotationBeanPostProcessor beanPostProcessor = getReferenceAnnotationBeanPostProcessor();
 
         Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> referenceBeanMap =
                 beanPostProcessor.getInjectedMethodReferenceBeanMap();
@@ -258,12 +260,12 @@ public class ReferenceAnnotationBeanPostProcessorTest {
 
         Collection<ReferenceBean> referenceBeans = referenceBeanManager.getReferences();
 
-        Assertions.assertEquals(5, referenceBeans.size());
+        Assertions.assertEquals(3, referenceBeans.size());
 
         for (ReferenceBean referenceBean : referenceBeans) {
             ReferenceConfig referenceConfig = referenceBean.getReferenceConfig();
             Assertions.assertNotNull(referenceConfig);
-            Assertions.assertNotNull(ReferenceConfigCache.getCache().get(referenceConfig));
+            Assertions.assertNotNull(referenceConfig.get());
         }
 
         ReferenceBean helloServiceReferenceBean = referenceBeanManager.getById("helloService");
@@ -275,6 +277,7 @@ public class ReferenceAnnotationBeanPostProcessorTest {
         ReferenceBean demoServiceReferenceBean = referenceBeanManager.getById("demoService");
         Assertions.assertEquals(demoServiceFromParentReferenceBean.getKey(), demoServiceReferenceBean.getKey());
         Assertions.assertEquals(demoServiceFromParentReferenceBean.getReferenceConfig(), demoServiceReferenceBean.getReferenceConfig());
+        Assertions.assertSame(demoServiceFromParentReferenceBean, demoServiceReferenceBean);
 
         ReferenceBean helloService2Bean = referenceBeanManager.getById("helloService2");
         Assertions.assertNotNull(helloService2Bean);
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java
index 2179306..2f2d293 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java
@@ -26,6 +26,7 @@ import org.apache.dubbo.config.MonitorConfig;
 import org.apache.dubbo.config.ProtocolConfig;
 import org.apache.dubbo.config.ProviderConfig;
 import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.config.context.ConfigManager;
 import org.apache.dubbo.config.spring.ZooKeeperServer;
 import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
@@ -68,6 +69,7 @@ public class SpringBootMultipleConfigPropsTest {
     @BeforeAll
     public static void setUp() {
         ZooKeeperServer.start();
+        DubboBootstrap.reset();
     }
 
     @Autowired
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer/PropertyConfigurerTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer/PropertyConfigurerTest.java
index 081def1..9916b80 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer/PropertyConfigurerTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer/PropertyConfigurerTest.java
@@ -48,7 +48,6 @@ public class PropertyConfigurerTest {
             providerContext.start();
 
             // clear config manager
-            //ApplicationModel.getConfigManager().clear();
             DubboBootstrap.reset(false);
 
             try {
@@ -56,6 +55,7 @@ public class PropertyConfigurerTest {
             } catch (InterruptedException e) {
             }
 
+            // Resolve placeholder by PropertyPlaceholderConfigurer in dubbo-consumer.xml, without import property source.
             AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class);
             context.start();
 
@@ -76,7 +76,6 @@ public class PropertyConfigurerTest {
     @EnableDubbo(scanBasePackages = "org.apache.dubbo.config.spring.propertyconfigurer.consumer")
     @ComponentScan(value = {"org.apache.dubbo.config.spring.propertyconfigurer.consumer"})
     @ImportResource("classpath:/org/apache/dubbo/config/spring/propertyconfigurer/consumer/dubbo-consumer.xml")
-    @PropertySource("classpath:/org/apache/dubbo/config/spring/propertyconfigurer/consumer/app.properties")
     static class ConsumerConfiguration {
         @Bean
         public DemoBeanFactoryPostProcessor bizBeanFactoryPostProcessor(HelloService service) {
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer2/PropertySourcesConfigurerTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer2/PropertySourcesConfigurerTest.java
index 40e0dfd..89b5298 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer2/PropertySourcesConfigurerTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer2/PropertySourcesConfigurerTest.java
@@ -21,7 +21,6 @@ import org.apache.dubbo.config.spring.ZooKeeperServer;
 import org.apache.dubbo.config.spring.api.HelloService;
 import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
 import org.apache.dubbo.config.spring.propertyconfigurer.consumer.DemoBeanFactoryPostProcessor;
-import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
@@ -30,7 +29,6 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.ImportResource;
-import org.springframework.context.annotation.PropertySource;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 
 public class PropertySourcesConfigurerTest {
@@ -56,6 +54,7 @@ public class PropertySourcesConfigurerTest {
             // reset config
             DubboBootstrap.reset(false);
 
+            // Resolve placeholder by PropertySourcesPlaceholderConfigurer in dubbo-consumer.xml, without import property source.
             AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class);
             try {
                 context.start();
@@ -76,7 +75,6 @@ public class PropertySourcesConfigurerTest {
     @EnableDubbo(scanBasePackages = "org.apache.dubbo.config.spring.propertyconfigurer.consumer2")
     @ComponentScan(value = {"org.apache.dubbo.config.spring.propertyconfigurer.consumer2"})
     @ImportResource("classpath:/org/apache/dubbo/config/spring/propertyconfigurer/consumer2/dubbo-consumer.xml")
-    @PropertySource("classpath:/org/apache/dubbo/config/spring/propertyconfigurer/consumer2/app.properties")
     static class ConsumerConfiguration {
         @Bean
         public DemoBeanFactoryPostProcessor bizBeanFactoryPostProcessor(HelloService service) {
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer3/PropertySourcesInJavaConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer3/PropertySourcesInJavaConfigTest.java
new file mode 100644
index 0000000..cd521119
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer3/PropertySourcesInJavaConfigTest.java
@@ -0,0 +1,160 @@
+/*
+ * 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.propertyconfigurer.consumer3;
+
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.config.spring.ZooKeeperServer;
+import org.apache.dubbo.config.spring.api.HelloService;
+import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
+import org.apache.dubbo.config.spring.propertyconfigurer.consumer.DemoBeanFactoryPostProcessor;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.ImportResource;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
+import org.springframework.core.io.ClassPathResource;
+
+public class PropertySourcesInJavaConfigTest {
+
+    private static final String SCAN_PACKAGE_NAME = "org.apache.dubbo.config.spring.propertyconfigurer.consumer3.notexist";
+    private static final String PACKAGE_PATH = "/org/apache/dubbo/config/spring/propertyconfigurer/consumer3";
+    private static final String PROVIDER_CONFIG_PATH = "org/apache/dubbo/config/spring/propertyconfigurer/provider/dubbo-provider.xml";
+
+    @BeforeAll
+    public static void setUp() {
+        ZooKeeperServer.start();
+    }
+
+    @BeforeEach
+    public void beforeTest() {
+        DubboBootstrap.reset();
+    }
+
+    @Test
+    public void testImportPropertySource() {
+
+        ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(PROVIDER_CONFIG_PATH);
+        try {
+            providerContext.start();
+
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+            }
+
+            // reset config
+            DubboBootstrap.reset(false);
+
+            // Resolve placeholder by import property sources
+            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class, ImportPropertyConfiguration.class);
+            try {
+                // expect auto create PropertySourcesPlaceholderConfigurer bean
+                String[] beanNames = context.getBeanNamesForType(PropertySourcesPlaceholderConfigurer.class);
+                Assertions.assertEquals(1, beanNames.length);
+                Assertions.assertEquals(PropertySourcesPlaceholderConfigurer.class.getName(), beanNames[0]);
+
+                HelloService service = (HelloService) context.getBean("demoService");
+                String result = service.sayHello("world");
+                System.out.println("result: " + result);
+                Assertions.assertEquals("Hello world, response from provider: 127.0.0.1:0", result);
+            } finally {
+                context.close();
+            }
+
+        } finally {
+            providerContext.close();
+        }
+    }
+
+    @Test
+    public void testCustomPropertySourceBean() {
+
+        ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(PROVIDER_CONFIG_PATH);
+        try {
+            providerContext.start();
+
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+            }
+
+            // reset config
+            DubboBootstrap.reset(false);
+
+            // Resolve placeholder by custom PropertySourcesPlaceholderConfigurer bean
+            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class, PropertyBeanConfiguration.class);
+            try {
+                // expect using custom PropertySourcesPlaceholderConfigurer bean
+                String[] beanNames = context.getBeanNamesForType(PropertySourcesPlaceholderConfigurer.class);
+                Assertions.assertEquals(1, beanNames.length);
+                Assertions.assertEquals("myPropertySourcesPlaceholderConfigurer", beanNames[0]);
+
+                HelloService service = (HelloService) context.getBean("demoService");
+                String result = service.sayHello("world");
+                System.out.println("result: " + result);
+                Assertions.assertEquals("Hello world, response from provider: 127.0.0.1:0", result);
+            } finally {
+                context.close();
+            }
+
+        } finally {
+            providerContext.close();
+        }
+    }
+
+    @Configuration
+    @EnableDubbo(scanBasePackages = SCAN_PACKAGE_NAME)
+    @ComponentScan(value = {SCAN_PACKAGE_NAME})
+    @ImportResource("classpath:" + PACKAGE_PATH + "/dubbo-consumer.xml")
+    static class ConsumerConfiguration {
+        @Bean
+        public DemoBeanFactoryPostProcessor bizBeanFactoryPostProcessor(HelloService service) {
+            return new DemoBeanFactoryPostProcessor(service);
+        }
+    }
+
+    @Configuration
+    @PropertySource("classpath:" + PACKAGE_PATH + "/app.properties")
+    static class ImportPropertyConfiguration {
+
+    }
+
+    @Configuration
+    static class PropertyBeanConfiguration {
+        @Bean
+        public MyPropertySourcesPlaceholderConfigurer myPropertySourcesPlaceholderConfigurer() {
+            MyPropertySourcesPlaceholderConfigurer placeholderConfigurer = new MyPropertySourcesPlaceholderConfigurer();
+            placeholderConfigurer.setLocation(new ClassPathResource(PACKAGE_PATH + "/app.properties"));
+            return placeholderConfigurer;
+        }
+    }
+
+    static class MyPropertySourcesPlaceholderConfigurer extends PropertySourcesPlaceholderConfigurer {
+        @Override
+        protected String convertProperty(String propertyName, String propertyValue) {
+            // .. do something ..
+            return propertyValue;
+        }
+    }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer3/app.properties b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer3/app.properties
new file mode 100644
index 0000000..fcda447
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer3/app.properties
@@ -0,0 +1,4 @@
+dubbo.registry.address=zookeeper://127.0.0.1:2181?registry-type=service
+biz.group=greeting
+biz.group2=group2
+dubbo.call-timeout=2000
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer3/dubbo-consumer.xml b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer3/dubbo-consumer.xml
new file mode 100644
index 0000000..c5233e7
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer3/dubbo-consumer.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
+       xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
+       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
+
+    <dubbo:application name="demo-consumer">
+    </dubbo:application>
+
+    <!--    <dubbo:metadata-report address="zookeeper://127.0.0.1:2181"/>-->
+
+    <dubbo:registry address="${dubbo.registry.address}"/>
+
+    <!--  timeout="${dubbo.call-timeout}"  -->
+    <dubbo:reference id="demoService" check="false" group="${biz.group}" timeout="${dubbo.call-timeout:foo-timeout}"
+                     interface="org.apache.dubbo.config.spring.api.HelloService"/>
+
+
+</beans>
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/ReferenceKeyTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/ReferenceKeyTest.java
index 521c561..02385c8 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/ReferenceKeyTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/ReferenceKeyTest.java
@@ -116,9 +116,10 @@ public class ReferenceKeyTest {
             Map<String, ReferenceBean> referenceBeanMap = context.getBeansOfType(ReferenceBean.class);
             Assertions.fail("Reference bean check failed");
         } catch (BeansException e) {
-            String s = e.toString();
-            Assertions.assertTrue(s.contains("Already exists another reference bean with the same bean name and type but difference attributes"), getStackTrace(e));
-            Assertions.assertTrue(s.contains("ConsumerConfiguration2.demoService"), getStackTrace(e));
+            String msg = getStackTrace(e);
+            Assertions.assertTrue(msg.contains("Found equivalent ReferenceConfig with unique service name [demo/org.apache.dubbo.config.spring.api.DemoService:1.2.3]"), msg);
+//            Assertions.assertTrue(msg.contains("Already exists another reference bean with the same bean name and type but difference attributes"), msg);
+//            Assertions.assertTrue(msg.contains("ConsumerConfiguration2.demoService"), msg);
         }
     }
 
@@ -143,7 +144,8 @@ public class ReferenceKeyTest {
             Map<String, ReferenceBean> referenceBeanMap = context.getBeansOfType(ReferenceBean.class);
             Assertions.fail("Reference bean check failed");
         } catch (BeansException e) {
-            Assertions.assertTrue(e.getMessage().contains("Duplicate spring bean name: demoService"), getStackTrace(e));
+            String msg = getStackTrace(e);
+            Assertions.assertTrue(msg.contains("Duplicate spring bean name: demoService"), msg);
         } finally {
             if (context != null) {
                 context.close();
@@ -171,9 +173,10 @@ public class ReferenceKeyTest {
             Map<String, ReferenceBean> referenceBeanMap = context.getBeansOfType(ReferenceBean.class);
             Assertions.fail("Reference bean check failed");
         } catch (BeansException e) {
-            String checkString = "Already exists another bean definition with the same bean name, but cannot rename the reference bean name";
-            Assertions.assertTrue(e.getMessage().contains(checkString), getStackTrace(e));
-            Assertions.assertTrue(e.getMessage().contains("ConsumerConfiguration6.demoService"), getStackTrace(e));
+            String checkString = "Already exists another bean definition with the same bean name [demoService], but cannot rename the reference bean name";
+            String msg = getStackTrace(e);
+            Assertions.assertTrue(msg.contains(checkString), msg);
+            Assertions.assertTrue(msg.contains("ConsumerConfiguration6.demoService"), msg);
         }
     }
 
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/localcallam/LocalCallMultipleReferenceAnnotationsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/localcallam/LocalCallMultipleReferenceAnnotationsTest.java
index 57d4abd..62cdb51 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/localcallam/LocalCallMultipleReferenceAnnotationsTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/reference/localcallam/LocalCallMultipleReferenceAnnotationsTest.java
@@ -71,15 +71,14 @@ public class LocalCallMultipleReferenceAnnotationsTest {
         Assertions.assertEquals("Hello world, response from provider: 127.0.0.1:0", demoResult);
 
         Map<String, ReferenceBean> referenceBeanMap = applicationContext.getBeansOfType(ReferenceBean.class);
-        Assertions.assertEquals(3, referenceBeanMap.size());
+        Assertions.assertEquals(2, referenceBeanMap.size());
         Assertions.assertTrue(referenceBeanMap.containsKey("&helloService"));
         Assertions.assertTrue(referenceBeanMap.containsKey("&demoHelloService"));
-        Assertions.assertTrue(referenceBeanMap.containsKey("&helloService3"));
 
         //helloService3 and demoHelloService share the same ReferenceConfig instance
-        ReferenceBean helloService3ReferenceBean = referenceBeanMap.get("&helloService3");
-        ReferenceBean demoHelloServiceReferenceBean = referenceBeanMap.get("&demoHelloService");
-        Assertions.assertTrue(helloService3ReferenceBean.getReferenceConfig() == demoHelloServiceReferenceBean.getReferenceConfig());
+        ReferenceBean helloService3ReferenceBean = applicationContext.getBean("&helloService3", ReferenceBean.class);
+        ReferenceBean demoHelloServiceReferenceBean = applicationContext.getBean("&demoHelloService", ReferenceBean.class);
+        Assertions.assertSame(helloService3ReferenceBean, demoHelloServiceReferenceBean);
 
     }
 
diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBinding2AutoConfigurationTest.java b/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBinding2AutoConfigurationTest.java
index b41cab1..6bc036e 100644
--- a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBinding2AutoConfigurationTest.java
+++ b/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBinding2AutoConfigurationTest.java
@@ -20,6 +20,7 @@ import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotati
 import org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor;
 
 import com.alibaba.spring.context.config.ConfigurationBeanBinder;
+import org.apache.dubbo.config.spring.util.DubboBeanUtils;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.ObjectProvider;
@@ -27,6 +28,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.PropertySource;
 import org.springframework.core.env.Environment;
 import org.springframework.test.context.junit4.SpringRunner;
@@ -64,23 +66,25 @@ public class DubboRelaxedBinding2AutoConfigurationTest {
     private ObjectProvider<ServiceAnnotationPostProcessor> serviceAnnotationPostProcessor;
 
     @Autowired
-    private ObjectProvider<ReferenceAnnotationBeanPostProcessor> referenceAnnotationBeanPostProcessor;
-
-    @Autowired
     private Environment environment;
 
     @Autowired
     private Map<String, Environment> environments;
 
+    @Autowired
+    private ApplicationContext applicationContext;
+
     @Test
     public void testBeans() {
 
+
         assertTrue(ClassUtils.isAssignableValue(BinderDubboConfigBinder.class, dubboConfigBinder));
 
         assertNotNull(serviceAnnotationPostProcessor);
         assertNotNull(serviceAnnotationPostProcessor.getIfAvailable());
+
+        ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor =  DubboBeanUtils.getReferenceAnnotationBeanPostProcessor(applicationContext);
         assertNotNull(referenceAnnotationBeanPostProcessor);
-        assertNotNull(referenceAnnotationBeanPostProcessor.getIfAvailable());
 
         assertNotNull(environment);
         assertNotNull(environments);
diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/AbstractDubboMetadata.java b/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/AbstractDubboMetadata.java
index 27ad5c9..4030f47 100644
--- a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/AbstractDubboMetadata.java
+++ b/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/AbstractDubboMetadata.java
@@ -20,6 +20,7 @@ import org.apache.dubbo.config.ProtocolConfig;
 import org.apache.dubbo.config.spring.ServiceBean;
 import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
 
+import org.apache.dubbo.config.spring.util.DubboBeanUtils;
 import org.springframework.beans.BeansException;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
@@ -38,7 +39,6 @@ import java.util.Date;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
-import static org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor.BEAN_NAME;
 import static org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors;
 import static org.springframework.util.ClassUtils.isPrimitiveOrWrapper;
 
@@ -113,7 +113,7 @@ public abstract class AbstractDubboMetadata implements ApplicationContextAware,
     }
 
     protected ReferenceAnnotationBeanPostProcessor getReferenceAnnotationBeanPostProcessor() {
-        return applicationContext.getBean(BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);
+        return DubboBeanUtils.getReferenceAnnotationBeanPostProcessor(applicationContext);
     }
 
     protected Map<String, ProtocolConfig> getProtocolConfigsBeanMap() {
diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTest.java b/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTest.java
index 6713dee..169d2ba 100644
--- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTest.java
+++ b/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTest.java
@@ -19,6 +19,7 @@ package org.apache.dubbo.spring.boot.autoconfigure;
 import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
 import org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor;
 
+import org.apache.dubbo.config.spring.util.DubboBeanUtils;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -26,6 +27,7 @@ import org.springframework.beans.factory.ObjectProvider;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.PropertySource;
 import org.springframework.test.context.junit4.SpringRunner;
 
@@ -47,13 +49,14 @@ public class CompatibleDubboAutoConfigurationTest {
     private ObjectProvider<ServiceAnnotationPostProcessor> serviceAnnotationPostProcessor;
 
     @Autowired
-    private ObjectProvider<ReferenceAnnotationBeanPostProcessor> referenceAnnotationBeanPostProcessor;
+    private ApplicationContext applicationContext;
 
     @Test
     public void testBeans() {
         Assert.assertNotNull(serviceAnnotationPostProcessor);
         Assert.assertNotNull(serviceAnnotationPostProcessor.getIfAvailable());
+
+        ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor =  DubboBeanUtils.getReferenceAnnotationBeanPostProcessor(applicationContext);
         Assert.assertNotNull(referenceAnnotationBeanPostProcessor);
-        Assert.assertNotNull(referenceAnnotationBeanPostProcessor.getIfAvailable());
     }
 }
diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTestWithoutProperties.java b/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTestWithoutProperties.java
index 2feb074..bca8630 100644
--- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTestWithoutProperties.java
+++ b/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTestWithoutProperties.java
@@ -20,6 +20,7 @@ import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
 import org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor;
 
+import org.apache.dubbo.config.spring.util.DubboBeanUtils;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -28,6 +29,7 @@ import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.ApplicationContext;
 import org.springframework.test.context.junit4.SpringRunner;
 
 /**
@@ -46,7 +48,7 @@ public class CompatibleDubboAutoConfigurationTestWithoutProperties {
     private ServiceAnnotationPostProcessor serviceAnnotationPostProcessor;
 
     @Autowired
-    private ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor;
+    private ApplicationContext applicationContext;
 
     @Before
     public void init() {
@@ -61,6 +63,8 @@ public class CompatibleDubboAutoConfigurationTestWithoutProperties {
     @Test
     public void testBeans() {
         Assert.assertNull(serviceAnnotationPostProcessor);
+
+        ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor =  DubboBeanUtils.getReferenceAnnotationBeanPostProcessor(applicationContext);
         Assert.assertNotNull(referenceAnnotationBeanPostProcessor);
     }
 }