You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by me...@apache.org on 2018/10/17 09:53:22 UTC

[incubator-dubbo] branch 2.6.x updated: Polish apache/incubator-dubbo#2235

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

mercyblitz pushed a commit to branch 2.6.x
in repository https://gitbox.apache.org/repos/asf/incubator-dubbo.git


The following commit(s) were added to refs/heads/2.6.x by this push:
     new 3571ea4  Polish apache/incubator-dubbo#2235
3571ea4 is described below

commit 3571ea4e69aaa30616de1096c636f03c92ae0c3f
Author: mercyblitz <ta...@taobao.com>
AuthorDate: Wed Oct 17 17:53:07 2018 +0800

    Polish apache/incubator-dubbo#2235
    
    Polish apache/incubator-dubbo#2251
    
    Polish apache/incubator-dubbo-spring-boot-project#243
---
 dependencies-bom/pom.xml                           |  11 +
 dubbo-config/dubbo-config-spring/pom.xml           |   7 +-
 .../alibaba/dubbo/config/spring/ServiceBean.java   |  56 ++-
 .../AbstractAnnotationConfigBeanBuilder.java       |   9 +-
 .../ReferenceAnnotationBeanPostProcessor.java      | 505 +++++----------------
 .../factory/annotation/ReferenceBeanBuilder.java   |  46 +-
 .../ServiceAnnotationBeanPostProcessor.java        |  22 +-
 .../factory/annotation/ServiceBeanNameBuilder.java | 111 +++++
 .../context/event/ServiceBeanExportedEvent.java    |  50 ++
 .../converter/StringArrayToMapConverter.java       |  38 --
 .../converter/StringArrayToStringConverter.java    |  37 --
 .../dubbo/config/spring/util/AnnotationUtils.java  |  44 +-
 .../ReferenceAnnotationBeanPostProcessorTest.java  | 128 +++---
 .../ServiceAnnotationBeanPostProcessorTest.java    |  45 +-
 .../ServiceAnnotationTestConfiguration.java        | 114 +++++
 .../annotation/ServiceBeanNameBuilderTest.java     |  75 +++
 .../converter/StringArrayToMapConverterTest.java   |  52 ---
 .../StringArrayToStringConverterTest.java          |  46 --
 18 files changed, 685 insertions(+), 711 deletions(-)

diff --git a/dependencies-bom/pom.xml b/dependencies-bom/pom.xml
index 752816b..e6bda8f 100644
--- a/dependencies-bom/pom.xml
+++ b/dependencies-bom/pom.xml
@@ -112,6 +112,7 @@
         <jaxb_version>2.2.7</jaxb_version>
         <activation_version>1.2.0</activation_version>
         <hessian_lite_version>3.2.4</hessian_lite_version>
+        <alibaba_spring_context_support_version>1.0.1</alibaba_spring_context_support_version>
     </properties>
 
     <dependencyManagement>
@@ -358,6 +359,16 @@
                 <artifactId>hessian-lite</artifactId>
                 <version>${hessian_lite_version}</version>
             </dependency>
+
+            <!-- Alibaba extensions -->
+
+            <!-- Spring Context Support -->
+            <dependency>
+                <groupId>com.alibaba.spring</groupId>
+                <artifactId>spring-context-support</artifactId>
+                <version>${alibaba_spring_context_support_version}</version>
+            </dependency>
+
             <!-- Test lib -->
             <dependency>
                 <groupId>org.apache.curator</groupId>
diff --git a/dubbo-config/dubbo-config-spring/pom.xml b/dubbo-config/dubbo-config-spring/pom.xml
index ad3ea15..8978c48 100644
--- a/dubbo-config/dubbo-config-spring/pom.xml
+++ b/dubbo-config/dubbo-config-spring/pom.xml
@@ -14,7 +14,8 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>com.alibaba</groupId>
@@ -52,6 +53,10 @@
             <artifactId>spring-context</artifactId>
         </dependency>
         <dependency>
+            <groupId>com.alibaba.spring</groupId>
+            <artifactId>spring-context-support</artifactId>
+        </dependency>
+        <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
             <scope>provided</scope>
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/ServiceBean.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/ServiceBean.java
index b38684b..06fa2b5 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/ServiceBean.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/ServiceBean.java
@@ -16,23 +16,16 @@
  */
 package com.alibaba.dubbo.config.spring;
 
-import com.alibaba.dubbo.config.ApplicationConfig;
-import com.alibaba.dubbo.config.ModuleConfig;
-import com.alibaba.dubbo.config.MonitorConfig;
-import com.alibaba.dubbo.config.ProtocolConfig;
-import com.alibaba.dubbo.config.ProviderConfig;
-import com.alibaba.dubbo.config.RegistryConfig;
-import com.alibaba.dubbo.config.ServiceConfig;
+import com.alibaba.dubbo.config.*;
 import com.alibaba.dubbo.config.annotation.Service;
+import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent;
 import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory;
 import org.springframework.aop.support.AopUtils;
 import org.springframework.beans.factory.BeanFactoryUtils;
 import org.springframework.beans.factory.BeanNameAware;
 import org.springframework.beans.factory.DisposableBean;
 import org.springframework.beans.factory.InitializingBean;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.context.ApplicationListener;
+import org.springframework.context.*;
 import org.springframework.context.event.ContextRefreshedEvent;
 import org.springframework.context.support.AbstractApplicationContext;
 
@@ -46,7 +39,9 @@ import java.util.Map;
  *
  * @export
  */
-public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware {
+public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean,
+        ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware,
+        ApplicationEventPublisherAware {
 
     private static final long serialVersionUID = 213195494150089726L;
 
@@ -60,6 +55,8 @@ public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean
 
     private transient boolean supportedApplicationListener;
 
+    private ApplicationEventPublisher applicationEventPublisher;
+
     public ServiceBean() {
         super();
         this.service = null;
@@ -265,6 +262,34 @@ public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean
         }
     }
 
+    /**
+     * Get the name of {@link ServiceBean}
+     *
+     * @return {@link ServiceBean}'s name
+     * @since 2.6.5
+     */
+    public String getBeanName() {
+        return this.beanName;
+    }
+
+    /**
+     * @since 2.6.5
+     */
+    @Override
+    public void export() {
+        super.export();
+        // Publish ServiceBeanExportedEvent
+        publishExportEvent();
+    }
+
+    /**
+     * @since 2.6.5
+     */
+    private void publishExportEvent() {
+        ServiceBeanExportedEvent exportEvent = new ServiceBeanExportedEvent(this);
+        applicationEventPublisher.publishEvent(exportEvent);
+    }
+
     @Override
     public void destroy() throws Exception {
         // This will only be called for singleton scope bean, and expected to be called by spring shutdown hook when BeanFactory/ApplicationContext destroys.
@@ -280,4 +305,13 @@ public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean
         }
         return super.getServiceClass(ref);
     }
+
+    /**
+     * @param applicationEventPublisher
+     * @since 2.6.5
+     */
+    @Override
+    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
+        this.applicationEventPublisher = applicationEventPublisher;
+    }
 }
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java
index fc8d3f4..28236be 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java
@@ -16,11 +16,7 @@
  */
 package com.alibaba.dubbo.config.spring.beans.factory.annotation;
 
-import com.alibaba.dubbo.config.AbstractInterfaceConfig;
-import com.alibaba.dubbo.config.ApplicationConfig;
-import com.alibaba.dubbo.config.ModuleConfig;
-import com.alibaba.dubbo.config.MonitorConfig;
-import com.alibaba.dubbo.config.RegistryConfig;
+import com.alibaba.dubbo.config.*;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.context.ApplicationContext;
@@ -34,6 +30,7 @@ import static com.alibaba.dubbo.config.spring.util.BeanFactoryUtils.getOptionalB
 
 /**
  * Abstract Configurable {@link Annotation} Bean Builder
+ *
  * @since 2.5.7
  */
 abstract class AbstractAnnotationConfigBeanBuilder<A extends Annotation, B extends AbstractInterfaceConfig> {
@@ -76,7 +73,7 @@ abstract class AbstractAnnotationConfigBeanBuilder<A extends Annotation, B exten
         configureBean(bean);
 
         if (logger.isInfoEnabled()) {
-            logger.info(bean + " has been built.");
+            logger.info("The bean[type:" + bean.getClass().getSimpleName() + "] has been built.");
         }
 
         return bean;
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java
index cfd7196..fc640ea 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java
@@ -18,488 +18,233 @@ package com.alibaba.dubbo.config.spring.beans.factory.annotation;
 
 import com.alibaba.dubbo.config.annotation.Reference;
 import com.alibaba.dubbo.config.spring.ReferenceBean;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.BeanUtils;
+import com.alibaba.dubbo.config.spring.ServiceBean;
+import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent;
+import com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor;
 import org.springframework.beans.BeansException;
-import org.springframework.beans.PropertyValues;
-import org.springframework.beans.factory.BeanClassLoaderAware;
-import org.springframework.beans.factory.BeanCreationException;
-import org.springframework.beans.factory.DisposableBean;
 import org.springframework.beans.factory.annotation.InjectionMetadata;
-import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
-import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
-import org.springframework.beans.factory.support.RootBeanDefinition;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
-import org.springframework.core.PriorityOrdered;
-import org.springframework.core.env.Environment;
-import org.springframework.util.ClassUtils;
-import org.springframework.util.ReflectionUtils;
-import org.springframework.util.StringUtils;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextRefreshedEvent;
 
-import java.beans.PropertyDescriptor;
 import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
+import java.lang.reflect.Proxy;
 import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.Collections;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
-import static org.springframework.core.BridgeMethodResolver.findBridgedMethod;
-import static org.springframework.core.BridgeMethodResolver.isVisibilityBridgeMethodPair;
-import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
-import static org.springframework.core.annotation.AnnotationUtils.getAnnotation;
-
 /**
  * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
  * that Consumer service {@link Reference} annotated fields
  *
  * @since 2.5.7
  */
-public class ReferenceAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
-        implements MergedBeanDefinitionPostProcessor, PriorityOrdered, ApplicationContextAware, BeanClassLoaderAware,
-        DisposableBean {
+public class ReferenceAnnotationBeanPostProcessor extends AnnotationInjectedBeanPostProcessor<Reference>
+        implements ApplicationContextAware, ApplicationListener {
 
     /**
      * The bean name of {@link ReferenceAnnotationBeanPostProcessor}
      */
     public static final String BEAN_NAME = "referenceAnnotationBeanPostProcessor";
 
-    private final Log logger = LogFactory.getLog(getClass());
-
-    private ApplicationContext applicationContext;
+    /**
+     * Cache size
+     */
+    private static final int CACHE_SIZE = Integer.getInteger(BEAN_NAME + ".cache.size", 32);
 
-    private ClassLoader classLoader;
+    private final ConcurrentMap<String, ReferenceBean<?>> referenceBeanCache =
+            new ConcurrentHashMap<String, ReferenceBean<?>>(CACHE_SIZE);
 
-    private final ConcurrentMap<String, ReferenceInjectionMetadata> injectionMetadataCache =
-            new ConcurrentHashMap<String, ReferenceInjectionMetadata>(256);
+    private final ConcurrentHashMap<String, ReferenceBeanInvocationHandler> localReferenceBeanInvocationHandlerCache =
+            new ConcurrentHashMap<String, ReferenceBeanInvocationHandler>(CACHE_SIZE);
 
-    private final ConcurrentMap<String, ReferenceBean<?>> referenceBeansCache =
-            new ConcurrentHashMap<String, ReferenceBean<?>>();
+    private final ConcurrentMap<InjectionMetadata.InjectedElement, ReferenceBean<?>> injectedFieldReferenceBeanCache =
+            new ConcurrentHashMap<InjectionMetadata.InjectedElement, ReferenceBean<?>>(CACHE_SIZE);
 
-    @Override
-    public PropertyValues postProcessPropertyValues(
-            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
-
-        InjectionMetadata metadata = findReferenceMetadata(beanName, bean.getClass(), pvs);
-        try {
-            metadata.inject(bean, beanName, pvs);
-        } catch (BeanCreationException ex) {
-            throw ex;
-        } catch (Throwable ex) {
-            throw new BeanCreationException(beanName, "Injection of @Reference dependencies failed", ex);
-        }
-        return pvs;
-    }
+    private final ConcurrentMap<InjectionMetadata.InjectedElement, ReferenceBean<?>> injectedMethodReferenceBeanCache =
+            new ConcurrentHashMap<InjectionMetadata.InjectedElement, ReferenceBean<?>>(CACHE_SIZE);
 
+    private ApplicationContext applicationContext;
 
     /**
-     * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link Reference @Reference} fields
+     * Gets all beans of {@link ReferenceBean}
      *
-     * @param beanClass The {@link Class} of Bean
-     * @return non-null {@link List}
+     * @return non-null read-only {@link Collection}
+     * @since 2.5.9
      */
-    private List<ReferenceFieldElement> findFieldReferenceMetadata(final Class<?> beanClass) {
-
-        final List<ReferenceFieldElement> elements = new LinkedList<ReferenceFieldElement>();
-
-        ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() {
-            @Override
-            public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
-
-                Reference reference = getAnnotation(field, Reference.class);
-
-                if (reference != null) {
-
-                    if (Modifier.isStatic(field.getModifiers())) {
-                        if (logger.isWarnEnabled()) {
-                            logger.warn("@Reference annotation is not supported on static fields: " + field);
-                        }
-                        return;
-                    }
-
-                    elements.add(new ReferenceFieldElement(field, reference));
-                }
-
-            }
-        });
-
-        return elements;
-
+    public Collection<ReferenceBean<?>> getReferenceBeans() {
+        return referenceBeanCache.values();
     }
 
     /**
-     * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link Reference @Reference} methods
+     * Get {@link ReferenceBean} {@link Map} in injected field.
      *
-     * @param beanClass The {@link Class} of Bean
-     * @return non-null {@link List}
+     * @return non-null {@link Map}
+     * @since 2.5.11
      */
-    private List<ReferenceMethodElement> findMethodReferenceMetadata(final Class<?> beanClass) {
-
-        final List<ReferenceMethodElement> elements = new LinkedList<ReferenceMethodElement>();
-
-        ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
-            @Override
-            public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
-
-                Method bridgedMethod = findBridgedMethod(method);
-
-                if (!isVisibilityBridgeMethodPair(method, bridgedMethod)) {
-                    return;
-                }
-
-                Reference reference = findAnnotation(bridgedMethod, Reference.class);
-
-                if (reference != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) {
-                    if (Modifier.isStatic(method.getModifiers())) {
-                        if (logger.isWarnEnabled()) {
-                            logger.warn("@Reference annotation is not supported on static methods: " + method);
-                        }
-                        return;
-                    }
-                    if (method.getParameterTypes().length == 0) {
-                        if (logger.isWarnEnabled()) {
-                            logger.warn("@Reference  annotation should only be used on methods with parameters: " +
-                                    method);
-                        }
-                    }
-                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass);
-                    elements.add(new ReferenceMethodElement(method, pd, reference));
-                }
-            }
-        });
-
-        return elements;
-
+    public Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> getInjectedFieldReferenceBeanMap() {
+        return Collections.unmodifiableMap(injectedFieldReferenceBeanCache);
     }
 
-
     /**
-     * @param beanClass
-     * @return
+     * Get {@link ReferenceBean} {@link Map} in injected method.
+     *
+     * @return non-null {@link Map}
+     * @since 2.5.11
      */
-    private ReferenceInjectionMetadata buildReferenceMetadata(final Class<?> beanClass) {
-        Collection<ReferenceFieldElement> fieldElements = findFieldReferenceMetadata(beanClass);
-        Collection<ReferenceMethodElement> methodElements = findMethodReferenceMetadata(beanClass);
-        return new ReferenceInjectionMetadata(beanClass, fieldElements, methodElements);
-
-    }
-
-    private InjectionMetadata findReferenceMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
-        // Fall back to class name as cache key, for backwards compatibility with custom callers.
-        String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
-        // Quick check on the concurrent map first, with minimal locking.
-        ReferenceInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
-        if (InjectionMetadata.needsRefresh(metadata, clazz)) {
-            synchronized (this.injectionMetadataCache) {
-                metadata = this.injectionMetadataCache.get(cacheKey);
-                if (InjectionMetadata.needsRefresh(metadata, clazz)) {
-                    if (metadata != null) {
-                        metadata.clear(pvs);
-                    }
-                    try {
-                        metadata = buildReferenceMetadata(clazz);
-                        this.injectionMetadataCache.put(cacheKey, metadata);
-                    } catch (NoClassDefFoundError err) {
-                        throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() +
-                                "] for reference metadata: could not find class that it depends on", err);
-                    }
-                }
-            }
-        }
-        return metadata;
-    }
-
-    @Override
-    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
-        this.applicationContext = applicationContext;
-    }
-
-    @Override
-    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
-        if (beanType != null) {
-            InjectionMetadata metadata = findReferenceMetadata(beanName, beanType, null);
-            metadata.checkConfigMembers(beanDefinition);
-        }
-    }
-
-    @Override
-    public int getOrder() {
-        return LOWEST_PRECEDENCE;
+    public Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> getInjectedMethodReferenceBeanMap() {
+        return Collections.unmodifiableMap(injectedMethodReferenceBeanCache);
     }
 
     @Override
-    public void destroy() throws Exception {
+    protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class<?> injectedType,
+                                       InjectionMetadata.InjectedElement injectedElement) throws Exception {
 
-        for (ReferenceBean referenceBean : referenceBeansCache.values()) {
-            if (logger.isInfoEnabled()) {
-                logger.info(referenceBean + " was destroying!");
-            }
-            referenceBean.destroy();
-        }
+        String referencedBeanName = buildReferencedBeanName(reference, injectedType);
 
-        injectionMetadataCache.clear();
-        referenceBeansCache.clear();
+        ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referencedBeanName, reference, injectedType, getClassLoader());
 
-        if (logger.isInfoEnabled()) {
-            logger.info(getClass() + " was destroying!");
-        }
+        cacheInjectedReferenceBean(referenceBean, injectedElement);
 
-    }
+        Object proxy = buildProxy(referencedBeanName, referenceBean, injectedType);
 
-    @Override
-    public void setBeanClassLoader(ClassLoader classLoader) {
-        this.classLoader = classLoader;
+        return proxy;
     }
 
-
-    /**
-     * Gets all beans of {@link ReferenceBean}
-     *
-     * @return non-null {@link Collection}
-     * @since 2.5.9
-     */
-    public Collection<ReferenceBean<?>> getReferenceBeans() {
-        return this.referenceBeansCache.values();
+    private Object buildProxy(String referencedBeanName, ReferenceBean referenceBean, Class<?> injectedType) {
+        InvocationHandler handler = buildInvocationHandler(referencedBeanName, referenceBean);
+        Object proxy = Proxy.newProxyInstance(getClassLoader(), new Class[]{injectedType}, handler);
+        return proxy;
     }
 
+    private InvocationHandler buildInvocationHandler(String referencedBeanName, ReferenceBean referenceBean) {
 
-    /**
-     * {@link Reference} {@link InjectionMetadata} implementation
-     *
-     * @since 2.5.11
-     */
-    private static class ReferenceInjectionMetadata extends InjectionMetadata {
-
-        private final Collection<ReferenceFieldElement> fieldElements;
+        ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.get(referencedBeanName);
 
-        private final Collection<ReferenceMethodElement> methodElements;
-
-
-        public ReferenceInjectionMetadata(Class<?> targetClass, Collection<ReferenceFieldElement> fieldElements,
-                                          Collection<ReferenceMethodElement> methodElements) {
-            super(targetClass, combine(fieldElements, methodElements));
-            this.fieldElements = fieldElements;
-            this.methodElements = methodElements;
+        if (handler == null) {
+            handler = new ReferenceBeanInvocationHandler(referenceBean);
         }
 
-        private static <T> Collection<T> combine(Collection<? extends T>... elements) {
-            List<T> allElements = new ArrayList<T>();
-            for (Collection<? extends T> e : elements) {
-                allElements.addAll(e);
-            }
-            return allElements;
-        }
-
-        public Collection<ReferenceFieldElement> getFieldElements() {
-            return fieldElements;
+        if (applicationContext.containsBean(referencedBeanName)) { // Is local @Service Bean or not ?
+            // ReferenceBeanInvocationHandler's initialization has to wait for current local @Service Bean has been exported.
+            localReferenceBeanInvocationHandlerCache.put(referencedBeanName, handler);
+        } else {
+            // Remote Reference Bean should initialize immediately
+            handler.init();
         }
 
-        public Collection<ReferenceMethodElement> getMethodElements() {
-            return methodElements;
-        }
+        return handler;
     }
 
-    /**
-     * {@link Reference} {@link Method} {@link InjectionMetadata.InjectedElement}
-     */
-    private class ReferenceMethodElement extends InjectionMetadata.InjectedElement {
+    private static class ReferenceBeanInvocationHandler implements InvocationHandler {
 
-        private final Method method;
+        private final ReferenceBean referenceBean;
 
-        private final Reference reference;
+        private Object bean;
 
-        private volatile ReferenceBean<?> referenceBean;
-
-        protected ReferenceMethodElement(Method method, PropertyDescriptor pd, Reference reference) {
-            super(method, pd);
-            this.method = method;
-            this.reference = reference;
+        private ReferenceBeanInvocationHandler(ReferenceBean referenceBean) {
+            this.referenceBean = referenceBean;
         }
 
         @Override
-        protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
-
-            Class<?> referenceClass = pd.getPropertyType();
-
-            referenceBean = buildReferenceBean(reference, referenceClass);
-
-            ReflectionUtils.makeAccessible(method);
-
-            method.invoke(bean, referenceBean.getObject());
-
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            return method.invoke(bean, args);
         }
 
-    }
-
-    /**
-     * {@link Reference} {@link Field} {@link InjectionMetadata.InjectedElement}
-     */
-    private class ReferenceFieldElement extends InjectionMetadata.InjectedElement {
-
-        private final Field field;
-
-        private final Reference reference;
-
-        private volatile ReferenceBean<?> referenceBean;
-
-        protected ReferenceFieldElement(Field field, Reference reference) {
-            super(field, null);
-            this.field = field;
-            this.reference = reference;
+        private void init() {
+            this.bean = referenceBean.get();
         }
+    }
 
-        @Override
-        protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
-
-            Class<?> referenceClass = field.getType();
+    @Override
+    protected String buildInjectedObjectCacheKey(Reference reference, Object bean, String beanName,
+                                                 Class<?> injectedType, InjectionMetadata.InjectedElement injectedElement) {
 
-            referenceBean = buildReferenceBean(reference, referenceClass);
+        String key = buildReferencedBeanName(reference, injectedType) +
+                "#source=" + (injectedElement.getMember());
 
-            ReflectionUtils.makeAccessible(field);
+        return key;
+    }
 
-            field.set(bean, referenceBean.getObject());
+    private String buildReferencedBeanName(Reference reference, Class<?> injectedType) {
 
-        }
+        ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, injectedType, getEnvironment());
 
+        return getEnvironment().resolvePlaceholders(builder.build());
     }
 
-    private ReferenceBean<?> buildReferenceBean(Reference reference, Class<?> referenceClass) throws Exception {
-
-        String referenceBeanCacheKey = generateReferenceBeanCacheKey(reference, referenceClass);
+    private ReferenceBean buildReferenceBeanIfAbsent(String referencedBeanName, Reference reference,
+                                                     Class<?> referencedType, ClassLoader classLoader)
+            throws Exception {
 
-        ReferenceBean<?> referenceBean = referenceBeansCache.get(referenceBeanCacheKey);
+        ReferenceBean<?> referenceBean = referenceBeanCache.get(referencedBeanName);
 
         if (referenceBean == null) {
-
             ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder
                     .create(reference, classLoader, applicationContext)
-                    .interfaceClass(referenceClass);
-
+                    .interfaceClass(referencedType);
             referenceBean = beanBuilder.build();
-
-            referenceBeansCache.putIfAbsent(referenceBeanCacheKey, referenceBean);
-
+            referenceBeanCache.put(referencedBeanName, referenceBean);
         }
 
         return referenceBean;
-
     }
 
-
-    /**
-     * Generate a cache key of {@link ReferenceBean}
-     *
-     * @param reference {@link Reference}
-     * @param beanClass {@link Class}
-     * @return
-     */
-    private String generateReferenceBeanCacheKey(Reference reference, Class<?> beanClass) {
-
-        String interfaceName = resolveInterfaceName(reference, beanClass);
-
-        String key = reference.url() + "/" + interfaceName +
-                "/" + reference.version() +
-                "/" + reference.group();
-
-        Environment environment = applicationContext.getEnvironment();
-
-        key = environment.resolvePlaceholders(key);
-
-        return key;
-
-    }
-
-    private static String resolveInterfaceName(Reference reference, Class<?> beanClass)
-            throws IllegalStateException {
-
-        String interfaceName;
-        if (!"".equals(reference.interfaceName())) {
-            interfaceName = reference.interfaceName();
-        } else if (!void.class.equals(reference.interfaceClass())) {
-            interfaceName = reference.interfaceClass().getName();
-        } else if (beanClass.isInterface()) {
-            interfaceName = beanClass.getName();
-        } else {
-            throw new IllegalStateException(
-                    "The @Reference undefined interfaceClass or interfaceName, and the property type "
-                            + beanClass.getName() + " is not a interface.");
+    private void cacheInjectedReferenceBean(ReferenceBean referenceBean,
+                                            InjectionMetadata.InjectedElement injectedElement) {
+        if (injectedElement.getMember() instanceof Field) {
+            injectedFieldReferenceBeanCache.put(injectedElement, referenceBean);
+        } else if (injectedElement.getMember() instanceof Method) {
+            injectedMethodReferenceBeanCache.put(injectedElement, referenceBean);
         }
-
-        return interfaceName;
-
     }
 
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        this.applicationContext = applicationContext;
+    }
 
-    /**
-     * Get {@link ReferenceBean} {@link Map} in injected field.
-     *
-     * @return non-null {@link Map}
-     * @since 2.5.11
-     */
-    public Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> getInjectedFieldReferenceBeanMap() {
-
-        Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> injectedElementReferenceBeanMap =
-                new LinkedHashMap<InjectionMetadata.InjectedElement, ReferenceBean<?>>();
-
-        for (ReferenceInjectionMetadata metadata : injectionMetadataCache.values()) {
-
-            Collection<ReferenceFieldElement> fieldElements = metadata.getFieldElements();
-
-            for (ReferenceFieldElement fieldElement : fieldElements) {
-
-                injectedElementReferenceBeanMap.put(fieldElement, fieldElement.referenceBean);
-
-            }
-
+    @Override
+    public void onApplicationEvent(ApplicationEvent event) {
+        if (event instanceof ServiceBeanExportedEvent) {
+            onServiceBeanExportEvent((ServiceBeanExportedEvent) event);
+        } else if (event instanceof ContextRefreshedEvent) {
+            onContextRefreshedEvent((ContextRefreshedEvent) event);
         }
-
-        return injectedElementReferenceBeanMap;
-
     }
 
-    /**
-     * Get {@link ReferenceBean} {@link Map} in injected method.
-     *
-     * @return non-null {@link Map}
-     * @since 2.5.11
-     */
-    public Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> getInjectedMethodReferenceBeanMap() {
-
-        Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> injectedElementReferenceBeanMap =
-                new LinkedHashMap<InjectionMetadata.InjectedElement, ReferenceBean<?>>();
-
-        for (ReferenceInjectionMetadata metadata : injectionMetadataCache.values()) {
-
-            Collection<ReferenceMethodElement> methodElements = metadata.getMethodElements();
-
-            for (ReferenceMethodElement methodElement : methodElements) {
-
-                injectedElementReferenceBeanMap.put(methodElement, methodElement.referenceBean);
-
-            }
+    private void onServiceBeanExportEvent(ServiceBeanExportedEvent event) {
+        ServiceBean serviceBean = event.getServiceBean();
+        initReferenceBeanInvocationHandler(serviceBean);
+    }
 
+    private void initReferenceBeanInvocationHandler(ServiceBean serviceBean) {
+        String serviceBeanName = serviceBean.getBeanName();
+        // Remove ServiceBean when it's exported
+        ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.remove(serviceBeanName);
+        // Initialize
+        if (handler != null) {
+            handler.init();
         }
-
-        return injectedElementReferenceBeanMap;
-
     }
 
-    private <T> T getFieldValue(Object object, String fieldName, Class<T> fieldType) {
-
-        Field field = ReflectionUtils.findField(object.getClass(), fieldName, fieldType);
-
-        ReflectionUtils.makeAccessible(field);
-
-        return (T) ReflectionUtils.getField(field, object);
+    private void onContextRefreshedEvent(ContextRefreshedEvent event) {
 
     }
 
 
-}
+    @Override
+    public void destroy() throws Exception {
+        super.destroy();
+        this.referenceBeanCache.clear();
+        this.localReferenceBeanInvocationHandlerCache.clear();
+        this.injectedFieldReferenceBeanCache.clear();
+        this.injectedMethodReferenceBeanCache.clear();
+    }
+}
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java
index 5d9418f..883a56a 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java
@@ -16,21 +16,23 @@
  */
 package com.alibaba.dubbo.config.spring.beans.factory.annotation;
 
+import com.alibaba.dubbo.common.utils.CollectionUtils;
 import com.alibaba.dubbo.config.ConsumerConfig;
 import com.alibaba.dubbo.config.annotation.Reference;
 import com.alibaba.dubbo.config.spring.ReferenceBean;
-import com.alibaba.dubbo.config.spring.convert.converter.StringArrayToMapConverter;
-import com.alibaba.dubbo.config.spring.convert.converter.StringArrayToStringConverter;
+import org.springframework.beans.propertyeditors.StringTrimmerEditor;
 import org.springframework.context.ApplicationContext;
-import org.springframework.core.convert.ConversionService;
-import org.springframework.core.convert.support.DefaultConversionService;
 import org.springframework.util.Assert;
 import org.springframework.util.ClassUtils;
 import org.springframework.util.StringUtils;
 import org.springframework.validation.DataBinder;
 
+import java.beans.PropertyEditorSupport;
+import java.util.Map;
+
 import static com.alibaba.dubbo.config.spring.util.BeanFactoryUtils.getOptionalBean;
 import static com.alibaba.dubbo.config.spring.util.ObjectUtils.of;
+import static org.springframework.util.StringUtils.commaDelimitedListToStringArray;
 
 /**
  * {@link ReferenceBean} Builder
@@ -39,6 +41,8 @@ import static com.alibaba.dubbo.config.spring.util.ObjectUtils.of;
  */
 class ReferenceBeanBuilder extends AbstractAnnotationConfigBeanBuilder<Reference, ReferenceBean> {
 
+    // Ignore those fields
+    static final String[] IGNORE_FIELD_NAMES = of("application", "module", "consumer", "monitor", "registry");
 
     private ReferenceBeanBuilder(Reference annotation, ClassLoader classLoader, ApplicationContext applicationContext) {
         super(annotation, classLoader, applicationContext);
@@ -93,20 +97,30 @@ class ReferenceBeanBuilder extends AbstractAnnotationConfigBeanBuilder<Reference
     protected void preConfigureBean(Reference reference, ReferenceBean referenceBean) {
         Assert.notNull(interfaceClass, "The interface class must set first!");
         DataBinder dataBinder = new DataBinder(referenceBean);
-        // Set ConversionService
-        dataBinder.setConversionService(getConversionService());
-        // Ignore those fields
-        String[] ignoreAttributeNames = of("application", "module", "consumer", "monitor", "registry");
-//        dataBinder.setDisallowedFields(ignoreAttributeNames);
+        // Register CustomEditors for special fields
+        dataBinder.registerCustomEditor(String.class, "filter", new StringTrimmerEditor(true));
+        dataBinder.registerCustomEditor(String.class, "listener", new StringTrimmerEditor(true));
+        dataBinder.registerCustomEditor(Map.class, "parameters", new PropertyEditorSupport() {
+
+            public void setAsText(String text) throws java.lang.IllegalArgumentException {
+                // Trim all whitespace
+                String content = StringUtils.trimAllWhitespace(text);
+                if (!StringUtils.hasText(content)) { // No content , ignore directly
+                    return;
+                }
+                // replace "=" to ","
+                content = StringUtils.replace(content, "=", ",");
+                // replace ":" to ","
+                content = StringUtils.replace(content, ":", ",");
+                // String[] to Map
+                Map<String, String> parameters = CollectionUtils.toStringMap(commaDelimitedListToStringArray(content));
+                setValue(parameters);
+            }
+        });
+
         // Bind annotation attributes
-        dataBinder.bind(new AnnotationPropertyValuesAdapter(reference, applicationContext.getEnvironment(), ignoreAttributeNames));
-    }
+        dataBinder.bind(new AnnotationPropertyValuesAdapter(reference, applicationContext.getEnvironment(), IGNORE_FIELD_NAMES));
 
-    private ConversionService getConversionService() {
-        DefaultConversionService conversionService = new DefaultConversionService();
-        conversionService.addConverter(new StringArrayToStringConverter());
-        conversionService.addConverter(new StringArrayToMapConverter());
-        return conversionService;
     }
 
 
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java
index 3560465..df46850 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java
@@ -71,7 +71,6 @@ import static org.springframework.util.ClassUtils.resolveClassName;
 public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware,
         ResourceLoaderAware, BeanClassLoaderAware {
 
-    private static final String SEPARATOR = ":";
 
     private final Logger logger = LoggerFactory.getLogger(getClass());
 
@@ -289,27 +288,10 @@ public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistr
      */
     private String generateServiceBeanName(Service service, Class<?> interfaceClass, String annotatedServiceBeanName) {
 
-        StringBuilder beanNameBuilder = new StringBuilder(ServiceBean.class.getSimpleName());
+        ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, interfaceClass, environment);
 
-        beanNameBuilder.append(SEPARATOR).append(annotatedServiceBeanName);
 
-        String interfaceClassName = interfaceClass.getName();
-
-        beanNameBuilder.append(SEPARATOR).append(interfaceClassName);
-
-        String version = service.version();
-
-        if (StringUtils.hasText(version)) {
-            beanNameBuilder.append(SEPARATOR).append(version);
-        }
-
-        String group = service.group();
-
-        if (StringUtils.hasText(group)) {
-            beanNameBuilder.append(SEPARATOR).append(group);
-        }
-
-        return beanNameBuilder.toString();
+        return builder.build();
 
     }
 
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java
new file mode 100644
index 0000000..b80840c
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java
@@ -0,0 +1,111 @@
+/*
+ * 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 com.alibaba.dubbo.config.spring.beans.factory.annotation;
+
+import com.alibaba.dubbo.config.annotation.Reference;
+import com.alibaba.dubbo.config.annotation.Service;
+import com.alibaba.dubbo.config.spring.ReferenceBean;
+import com.alibaba.dubbo.config.spring.ServiceBean;
+import org.springframework.core.env.Environment;
+import org.springframework.util.StringUtils;
+
+import static com.alibaba.dubbo.config.spring.util.AnnotationUtils.resolveInterfaceName;
+
+/**
+ * Dubbo {@link Service @Service} Bean Builder
+ *
+ * @see Service
+ * @see Reference
+ * @see ServiceBean
+ * @see ReferenceBean
+ * @since 2.6.5
+ */
+class ServiceBeanNameBuilder {
+
+    private static final String SEPARATOR = ":";
+
+    private final String interfaceClassName;
+
+    private final Environment environment;
+
+    // Optional
+    private String version;
+
+    private String group;
+
+    private ServiceBeanNameBuilder(String interfaceClassName, Environment environment) {
+        this.interfaceClassName = interfaceClassName;
+        this.environment = environment;
+    }
+
+    private ServiceBeanNameBuilder(Class<?> interfaceClass, Environment environment) {
+        this(interfaceClass.getName(), environment);
+    }
+
+    private ServiceBeanNameBuilder(Service service, Class<?> interfaceClass, Environment environment) {
+        this(resolveInterfaceName(service, interfaceClass), environment);
+        this.group(service.group());
+        this.version(service.version());
+    }
+
+    private ServiceBeanNameBuilder(Reference reference, Class<?> interfaceClass, Environment environment) {
+        this(resolveInterfaceName(reference, interfaceClass), environment);
+        this.group(reference.group());
+        this.version(reference.version());
+    }
+
+    public static ServiceBeanNameBuilder create(Class<?> interfaceClass, Environment environment) {
+        return new ServiceBeanNameBuilder(interfaceClass, environment);
+    }
+
+    public static ServiceBeanNameBuilder create(Service service, Class<?> interfaceClass, Environment environment) {
+        return new ServiceBeanNameBuilder(service, interfaceClass, environment);
+    }
+
+    public static ServiceBeanNameBuilder create(Reference reference, Class<?> interfaceClass, Environment environment) {
+        return new ServiceBeanNameBuilder(reference, interfaceClass, environment);
+    }
+
+    private static void append(StringBuilder builder, String value) {
+        if (StringUtils.hasText(value)) {
+            builder.append(value).append(SEPARATOR);
+        }
+    }
+
+    public ServiceBeanNameBuilder group(String group) {
+        this.group = group;
+        return this;
+    }
+
+    public ServiceBeanNameBuilder version(String version) {
+        this.version = version;
+        return this;
+    }
+
+    public String build() {
+        StringBuilder beanNameBuilder = new StringBuilder("ServiceBean").append(SEPARATOR);
+        // Required
+        append(beanNameBuilder, interfaceClassName);
+        // Optional
+        append(beanNameBuilder, version);
+        append(beanNameBuilder, group);
+        // Build and remove last ":"
+        String rawBeanName = beanNameBuilder.substring(0, beanNameBuilder.length() - 1);
+        // Resolve placeholders
+        return environment.resolvePlaceholders(rawBeanName);
+    }
+}
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/event/ServiceBeanExportedEvent.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/event/ServiceBeanExportedEvent.java
new file mode 100644
index 0000000..3b14d01
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/event/ServiceBeanExportedEvent.java
@@ -0,0 +1,50 @@
+/*
+ * 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 com.alibaba.dubbo.config.spring.context.event;
+
+import com.alibaba.dubbo.config.spring.ServiceBean;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
+
+/**
+ * A {@link ApplicationEvent} after {@link ServiceBean} {@link ServiceBean#export() export} invocation
+ *
+ * @see ApplicationEvent
+ * @see ApplicationListener
+ * @see ServiceBean
+ * @since 2.6.5
+ */
+public class ServiceBeanExportedEvent extends ApplicationEvent {
+
+    /**
+     * Create a new ApplicationEvent.
+     *
+     * @param serviceBean {@link ServiceBean} bean
+     */
+    public ServiceBeanExportedEvent(ServiceBean serviceBean) {
+        super(serviceBean);
+    }
+
+    /**
+     * Get {@link ServiceBean} instance
+     *
+     * @return non-null
+     */
+    public ServiceBean getServiceBean() {
+        return (ServiceBean) super.getSource();
+    }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToMapConverter.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToMapConverter.java
deleted file mode 100644
index 56c6d4c..0000000
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToMapConverter.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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 com.alibaba.dubbo.config.spring.convert.converter;
-
-import com.alibaba.dubbo.common.utils.CollectionUtils;
-import org.springframework.core.convert.converter.Converter;
-import org.springframework.util.ObjectUtils;
-
-import java.util.Map;
-
-/**
- * {@link String}[] to {@link Map} {@link Converter}
- *
- * @see CollectionUtils#toStringMap(String[])
- * @since 2.5.11
- */
-public class StringArrayToMapConverter implements Converter<String[], Map<String, String>> {
-
-    @Override
-    public Map<String, String> convert(String[] source) {
-        return ObjectUtils.isEmpty(source) ? null : CollectionUtils.toStringMap(source);
-    }
-
-}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToStringConverter.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToStringConverter.java
deleted file mode 100644
index 23e948b..0000000
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToStringConverter.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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 com.alibaba.dubbo.config.spring.convert.converter;
-
-import org.springframework.core.convert.converter.Converter;
-import org.springframework.util.ObjectUtils;
-import org.springframework.util.StringUtils;
-
-
-/**
- * String[] to String {@ConditionalGenericConverter}
- *
- * @see StringUtils#arrayToCommaDelimitedString(Object[])
- * @since 2.5.11
- */
-public class StringArrayToStringConverter implements Converter<String[], String> {
-
-    @Override
-    public String convert(String[] source) {
-        return ObjectUtils.isEmpty(source) ? null : StringUtils.arrayToCommaDelimitedString(source);
-    }
-
-}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotationUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotationUtils.java
index aa15e56..4ac4a82 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotationUtils.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotationUtils.java
@@ -16,6 +16,8 @@
  */
 package com.alibaba.dubbo.config.spring.util;
 
+import com.alibaba.dubbo.config.annotation.Reference;
+import com.alibaba.dubbo.config.annotation.Service;
 import org.springframework.core.env.PropertyResolver;
 
 import java.lang.annotation.Annotation;
@@ -86,4 +88,44 @@ public class AnnotationUtils {
 
     }
 
-}
+    public static String resolveInterfaceName(Service service, Class<?> defaultInterfaceClass)
+            throws IllegalStateException {
+
+        String interfaceName;
+        if (!"".equals(service.interfaceName())) {
+            interfaceName = service.interfaceName();
+        } else if (!void.class.equals(service.interfaceClass())) {
+            interfaceName = service.interfaceClass().getName();
+        } else if (defaultInterfaceClass.isInterface()) {
+            interfaceName = defaultInterfaceClass.getName();
+        } else {
+            throw new IllegalStateException(
+                    "The @Service undefined interfaceClass or interfaceName, and the type "
+                            + defaultInterfaceClass.getName() + " is not a interface.");
+        }
+
+        return interfaceName;
+
+    }
+
+    public static String resolveInterfaceName(Reference reference, Class<?> defaultInterfaceClass)
+            throws IllegalStateException {
+
+        String interfaceName;
+        if (!"".equals(reference.interfaceName())) {
+            interfaceName = reference.interfaceName();
+        } else if (!void.class.equals(reference.interfaceClass())) {
+            interfaceName = reference.interfaceClass().getName();
+        } else if (defaultInterfaceClass.isInterface()) {
+            interfaceName = defaultInterfaceClass.getName();
+        } else {
+            throw new IllegalStateException(
+                    "The @Reference undefined interfaceClass or interfaceName, and the type "
+                            + defaultInterfaceClass.getName() + " is not a interface.");
+        }
+
+        return interfaceName;
+
+    }
+
+}
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
index a1b5807..eba43b2 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
@@ -19,26 +19,23 @@ package com.alibaba.dubbo.config.spring.beans.factory.annotation;
 import com.alibaba.dubbo.config.annotation.Reference;
 import com.alibaba.dubbo.config.spring.ReferenceBean;
 import com.alibaba.dubbo.config.spring.api.DemoService;
-import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
-import org.junit.After;
 import org.junit.Assert;
-import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.InjectionMetadata;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ConfigurableApplicationContext;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import org.springframework.context.annotation.ImportResource;
+import org.springframework.context.annotation.Bean;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
 
 import java.util.Collection;
 import java.util.Map;
 
 import static com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor.BEAN_NAME;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.CoreMatchers.*;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 /**
@@ -46,50 +43,48 @@ import static org.hamcrest.MatcherAssert.assertThat;
  *
  * @since 2.5.7
  */
+@RunWith(SpringRunner.class)
+@ContextConfiguration(
+        classes = {
+                ServiceAnnotationTestConfiguration.class,
+                ReferenceAnnotationBeanPostProcessorTest.class
+        })
+@TestPropertySource(properties = {
+        "packagesToScan = com.alibaba.dubbo.config.spring.context.annotation.provider",
+        "consumer.version = ${demo.service.version}",
+        "consumer.url = dubbo://127.0.0.1:12345",
+})
 public class ReferenceAnnotationBeanPostProcessorTest {
 
-    private ConfigurableApplicationContext providerApplicationContext;
-
-    @BeforeClass
-    public static void prepare() {
-        System.setProperty("provider.version", "1.2");
-        System.setProperty("package1", "com.alibaba.dubbo.config.spring.annotation.provider");
-        System.setProperty("packagesToScan", "${package1}");
-        System.setProperty("consumer.version", "1.2");
-        System.setProperty("consumer.url", "dubbo://127.0.0.1:12345");
+    @Bean
+    public TestBean testBean() {
+        return new TestBean();
     }
 
-    @Before
-    public void init() {
-        // Starts Provider
-        providerApplicationContext = new AnnotationConfigApplicationContext(ServiceAnnotationBeanPostProcessorTest.TestConfiguration.class);
+    @Bean(BEAN_NAME)
+    public ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor() {
+        return new ReferenceAnnotationBeanPostProcessor();
     }
 
-    @After
-    public void destroy() {
-        // Shutdowns Provider
-        providerApplicationContext.close();
-    }
+    @Autowired
+    private ConfigurableApplicationContext context;
 
     @Test
     public void test() throws Exception {
 
-        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class);
-
         TestBean testBean = context.getBean(TestBean.class);
 
+        DemoService demoService = testBean.getDemoService();
+
+        Assert.assertEquals("Hello,Mercy", demoService.sayName("Mercy"));
+
         Assert.assertNotNull(testBean.getDemoServiceFromAncestor());
         Assert.assertNotNull(testBean.getDemoServiceFromParent());
         Assert.assertNotNull(testBean.getDemoService());
 
-        Assert.assertEquals(testBean.getDemoServiceFromAncestor(), testBean.getDemoServiceFromParent());
-        Assert.assertEquals(testBean.getDemoService(), testBean.getDemoServiceFromParent());
-
-        DemoService demoService = testBean.getDemoService();
-
-        Assert.assertEquals("annotation:Mercy", demoService.sayName("Mercy"));
-
-        context.close();
+        Assert.assertEquals("Hello,Mercy", testBean.getDemoServiceFromAncestor().sayName("Mercy"));
+        Assert.assertEquals("Hello,Mercy", testBean.getDemoServiceFromParent().sayName("Mercy"));
+        Assert.assertEquals("Hello,Mercy", testBean.getDemoService().sayName("Mercy"));
 
     }
 
@@ -99,8 +94,6 @@ public class ReferenceAnnotationBeanPostProcessorTest {
     @Test
     public void testGetReferenceBeans() {
 
-        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class);
-
         ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME,
                 ReferenceAnnotationBeanPostProcessor.class);
 
@@ -112,17 +105,13 @@ public class ReferenceAnnotationBeanPostProcessorTest {
 
         TestBean testBean = context.getBean(TestBean.class);
 
-        Assert.assertEquals(referenceBean.get(), testBean.getDemoServiceFromAncestor());
-        Assert.assertEquals(referenceBean.get(), testBean.getDemoServiceFromParent());
-        Assert.assertEquals(referenceBean.get(), testBean.getDemoService());
+        Assert.assertNotNull(referenceBean.get());
 
     }
 
     @Test
     public void testGetInjectedFieldReferenceBeanMap() {
 
-        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class);
-
         ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME,
                 ReferenceAnnotationBeanPostProcessor.class);
 
@@ -136,12 +125,12 @@ public class ReferenceAnnotationBeanPostProcessorTest {
 
             InjectionMetadata.InjectedElement injectedElement = entry.getKey();
 
-            Assert.assertEquals("com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor$ReferenceFieldElement",
+            Assert.assertEquals("com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedFieldElement",
                     injectedElement.getClass().getName());
 
             ReferenceBean<?> referenceBean = entry.getValue();
 
-            Assert.assertEquals("1.2", referenceBean.getVersion());
+            Assert.assertEquals("2.5.7", referenceBean.getVersion());
             Assert.assertEquals("dubbo://127.0.0.1:12345", referenceBean.getUrl());
 
         }
@@ -151,8 +140,6 @@ public class ReferenceAnnotationBeanPostProcessorTest {
     @Test
     public void testGetInjectedMethodReferenceBeanMap() {
 
-        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class);
-
         ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME,
                 ReferenceAnnotationBeanPostProcessor.class);
 
@@ -166,36 +153,35 @@ public class ReferenceAnnotationBeanPostProcessorTest {
 
             InjectionMetadata.InjectedElement injectedElement = entry.getKey();
 
-            Assert.assertEquals("com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor$ReferenceMethodElement",
+            Assert.assertEquals("com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedMethodElement",
                     injectedElement.getClass().getName());
 
             ReferenceBean<?> referenceBean = entry.getValue();
 
-            Assert.assertEquals("1.2", referenceBean.getVersion());
+            Assert.assertEquals("2.5.7", referenceBean.getVersion());
             Assert.assertEquals("dubbo://127.0.0.1:12345", referenceBean.getUrl());
 
         }
 
     }
 
-    @Test
-    public void testModuleInfo() {
-        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class);
-
-        ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME,
-                ReferenceAnnotationBeanPostProcessor.class);
-
-
-        Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> referenceBeanMap =
-                beanPostProcessor.getInjectedMethodReferenceBeanMap();
-
-        for (Map.Entry<InjectionMetadata.InjectedElement, ReferenceBean<?>> entry : referenceBeanMap.entrySet()) {
-            ReferenceBean<?> referenceBean = entry.getValue();
-
-            assertThat(referenceBean.getModule().getName(),is("defaultModule"));
-            assertThat(referenceBean.getMonitor(), not(nullValue()));
-        }
-    }
+//    @Test
+//    public void testModuleInfo() {
+//
+//        ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME,
+//                ReferenceAnnotationBeanPostProcessor.class);
+//
+//
+//        Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> referenceBeanMap =
+//                beanPostProcessor.getInjectedMethodReferenceBeanMap();
+//
+//        for (Map.Entry<InjectionMetadata.InjectedElement, ReferenceBean<?>> entry : referenceBeanMap.entrySet()) {
+//            ReferenceBean<?> referenceBean = entry.getValue();
+//
+//            assertThat(referenceBean.getModule().getName(), is("defaultModule"));
+//            assertThat(referenceBean.getMonitor(), not(nullValue()));
+//        }
+//    }
 
     private static class AncestorBean {
 
@@ -209,7 +195,7 @@ public class ReferenceAnnotationBeanPostProcessorTest {
             return demoServiceFromAncestor;
         }
 
-        @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345")
+        @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345")
         public void setDemoServiceFromAncestor(DemoService demoServiceFromAncestor) {
             this.demoServiceFromAncestor = demoServiceFromAncestor;
         }
@@ -233,8 +219,6 @@ public class ReferenceAnnotationBeanPostProcessorTest {
 
     }
 
-    @ImportResource("META-INF/spring/dubbo-annotation-consumer.xml")
-    @DubboComponentScan(basePackageClasses = ReferenceAnnotationBeanPostProcessorTest.class)
     static class TestBean extends ParentBean {
 
         private DemoService demoService;
@@ -246,7 +230,7 @@ public class ReferenceAnnotationBeanPostProcessorTest {
             return demoService;
         }
 
-        @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345")
+        @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345")
         public void setDemoService(DemoService demoService) {
             this.demoService = demoService;
         }
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessorTest.java
index c096441..6133c48 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessorTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessorTest.java
@@ -25,9 +25,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
 import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.ImportResource;
-import org.springframework.context.annotation.PropertySource;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.TestPropertySource;
 import org.springframework.test.context.junit4.SpringRunner;
@@ -41,17 +38,25 @@ import java.util.Map;
  */
 @RunWith(SpringRunner.class)
 @ContextConfiguration(
-        classes = {ServiceAnnotationBeanPostProcessorTest.TestConfiguration.class})
+        classes = {
+                ServiceAnnotationTestConfiguration.class,
+                ServiceAnnotationBeanPostProcessorTest.class
+        })
 @TestPropertySource(properties = {
-        "package1 = com.alibaba.dubbo.config.spring.context.annotation",
-        "packagesToScan = ${package1}",
-        "provider.version = 1.2"
+        "provider.package = com.alibaba.dubbo.config.spring.context.annotation.provider",
+        "packagesToScan = ${provider.package}",
 })
 public class ServiceAnnotationBeanPostProcessorTest {
 
     @Autowired
     private ConfigurableListableBeanFactory beanFactory;
 
+    @Bean
+    public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor2
+            (@Value("${packagesToScan}") String... packagesToScan) {
+        return new ServiceAnnotationBeanPostProcessor(packagesToScan);
+    }
+
     @Test
     public void test() {
 
@@ -61,38 +66,16 @@ public class ServiceAnnotationBeanPostProcessorTest {
 
         Map<String, ServiceBean> serviceBeansMap = beanFactory.getBeansOfType(ServiceBean.class);
 
-        Assert.assertEquals(3, serviceBeansMap.size());
+        Assert.assertEquals(2, serviceBeansMap.size());
 
         Map<String, ServiceAnnotationBeanPostProcessor> beanPostProcessorsMap =
                 beanFactory.getBeansOfType(ServiceAnnotationBeanPostProcessor.class);
 
-        Assert.assertEquals(4, beanPostProcessorsMap.size());
+        Assert.assertEquals(2, beanPostProcessorsMap.size());
 
-        Assert.assertTrue(beanPostProcessorsMap.containsKey("doubleServiceAnnotationBeanPostProcessor"));
-        Assert.assertTrue(beanPostProcessorsMap.containsKey("emptyServiceAnnotationBeanPostProcessor"));
         Assert.assertTrue(beanPostProcessorsMap.containsKey("serviceAnnotationBeanPostProcessor"));
         Assert.assertTrue(beanPostProcessorsMap.containsKey("serviceAnnotationBeanPostProcessor2"));
 
     }
 
-    @ImportResource("META-INF/spring/dubbo-annotation-provider.xml")
-    @PropertySource("META-INF/default.properties")
-    @ComponentScan("com.alibaba.dubbo.config.spring.context.annotation.provider")
-    public static class TestConfiguration {
-
-        @Bean
-        public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor
-                (@Value("${packagesToScan}") String... packagesToScan) {
-            return new ServiceAnnotationBeanPostProcessor(packagesToScan);
-        }
-
-        @Bean
-        public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor2
-                (@Value("${packagesToScan}") String... packagesToScan) {
-            return new ServiceAnnotationBeanPostProcessor(packagesToScan);
-        }
-
-
-    }
-
 }
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationTestConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationTestConfiguration.java
new file mode 100644
index 0000000..2e20797f
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationTestConfiguration.java
@@ -0,0 +1,114 @@
+/*
+ * 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 com.alibaba.dubbo.config.spring.beans.factory.annotation;
+
+import com.alibaba.dubbo.config.ApplicationConfig;
+import com.alibaba.dubbo.config.ProtocolConfig;
+import com.alibaba.dubbo.config.RegistryConfig;
+import com.alibaba.dubbo.config.annotation.Service;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Primary;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionException;
+import org.springframework.transaction.TransactionStatus;
+
+/**
+ * {@link Service} Bean
+ *
+ * @since 2.6.5
+ */
+@PropertySource("META-INF/default.properties")
+public class ServiceAnnotationTestConfiguration {
+
+    /**
+     * Current application configuration, to replace XML config:
+     * <prev>
+     * &lt;dubbo:application name="dubbo-annotation-provider"/&gt;
+     * </prev>
+     *
+     * @return {@link ApplicationConfig} Bean
+     */
+    @Bean("dubbo-annotation-provider")
+    public ApplicationConfig applicationConfig() {
+        ApplicationConfig applicationConfig = new ApplicationConfig();
+        applicationConfig.setName("dubbo-annotation-provider");
+        return applicationConfig;
+    }
+
+    /**
+     * Current registry center configuration, to replace XML config:
+     * <prev>
+     * &lt;dubbo:registry id="my-registry" address="N/A"/&gt;
+     * </prev>
+     *
+     * @return {@link RegistryConfig} Bean
+     */
+    @Bean("my-registry")
+    public RegistryConfig registryConfig() {
+        RegistryConfig registryConfig = new RegistryConfig();
+        registryConfig.setAddress("N/A");
+        return registryConfig;
+    }
+
+    /**
+     * Current protocol configuration, to replace XML config:
+     * <prev>
+     * &lt;dubbo:protocol name="dubbo" port="12345"/&gt;
+     * </prev>
+     *
+     * @return {@link ProtocolConfig} Bean
+     */
+    @Bean("dubbo")
+    public ProtocolConfig protocolConfig() {
+        ProtocolConfig protocolConfig = new ProtocolConfig();
+        protocolConfig.setName("dubbo");
+        protocolConfig.setPort(12345);
+        return protocolConfig;
+    }
+
+    @Primary
+    @Bean
+    public PlatformTransactionManager platformTransactionManager() {
+        return new PlatformTransactionManager() {
+
+            @Override
+            public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
+                return null;
+            }
+
+            @Override
+            public void commit(TransactionStatus status) throws TransactionException {
+
+            }
+
+            @Override
+            public void rollback(TransactionStatus status) throws TransactionException {
+
+            }
+        };
+    }
+
+    @Bean
+    public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor
+            (@Value("${packagesToScan}") String... packagesToScan) {
+        return new ServiceAnnotationBeanPostProcessor(packagesToScan);
+    }
+
+}
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java
new file mode 100644
index 0000000..8ee0c4b
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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 com.alibaba.dubbo.config.spring.beans.factory.annotation;
+
+import com.alibaba.dubbo.config.annotation.Reference;
+import com.alibaba.dubbo.config.annotation.Service;
+import com.alibaba.dubbo.config.spring.api.DemoService;
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.mock.env.MockEnvironment;
+import org.springframework.util.ReflectionUtils;
+
+import static com.alibaba.dubbo.config.spring.beans.factory.annotation.ServiceBeanNameBuilderTest.GROUP;
+import static com.alibaba.dubbo.config.spring.beans.factory.annotation.ServiceBeanNameBuilderTest.VERSION;
+
+/**
+ * {@link ServiceBeanNameBuilder} Test
+ *
+ * @see ServiceBeanNameBuilder
+ * @since 2.6.5
+ */
+@Service(interfaceClass = DemoService.class, group = GROUP, version = VERSION,
+        application = "application", module = "module", registry = {"1", "2", "3"})
+public class ServiceBeanNameBuilderTest {
+
+    @Reference(interfaceClass = DemoService.class, group = "DUBBO", version = "1.0.0",
+            application = "application", module = "module", registry = {"1", "2", "3"})
+    static final Class<?> INTERFACE_CLASS = DemoService.class;
+
+    static final String GROUP = "DUBBO";
+
+    static final String VERSION = "1.0.0";
+
+    static final String BEAN_NAME = "ServiceBean:com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO";
+
+    private MockEnvironment environment = new MockEnvironment();
+
+    @Test
+    public void testRequiredAttributes() {
+        ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(INTERFACE_CLASS, environment);
+        Assert.assertEquals("ServiceBean:com.alibaba.dubbo.config.spring.api.DemoService", builder.build());
+    }
+
+    @Test
+    public void testServiceAnnotation() {
+        Service service = AnnotationUtils.getAnnotation(ServiceBeanNameBuilderTest.class, Service.class);
+        ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, INTERFACE_CLASS, environment);
+        Assert.assertEquals(BEAN_NAME,
+                builder.build());
+    }
+
+    @Test
+    public void testReferenceAnnotation() {
+        Reference reference = AnnotationUtils.getAnnotation(ReflectionUtils.findField(ServiceBeanNameBuilderTest.class, "INTERFACE_CLASS"), Reference.class);
+        ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, INTERFACE_CLASS, environment);
+        Assert.assertEquals(BEAN_NAME,
+                builder.build());
+    }
+
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToMapConverterTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToMapConverterTest.java
deleted file mode 100644
index 51be7c3..0000000
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToMapConverterTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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 com.alibaba.dubbo.config.spring.convert.converter;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-/**
- * {@link StringArrayToMapConverter} Test
- */
-public class StringArrayToMapConverterTest {
-
-    @Test
-    public void testConvert() {
-
-        StringArrayToMapConverter converter = new StringArrayToMapConverter();
-
-        Map<String, String> value = converter.convert(new String[]{"Hello", "World"});
-
-        Map<String, String> expected = new LinkedHashMap<String, String>();
-
-        expected.put("Hello", "World");
-
-        Assert.assertEquals(expected, value);
-
-        value = converter.convert(new String[]{});
-
-        Assert.assertNull(value);
-
-        value = converter.convert(null);
-
-        Assert.assertNull(value);
-
-    }
-}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToStringConverterTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToStringConverterTest.java
deleted file mode 100644
index 67e8247..0000000
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToStringConverterTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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 com.alibaba.dubbo.config.spring.convert.converter;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-/**
- * {@link StringArrayToStringConverter} Test
- */
-public class StringArrayToStringConverterTest {
-
-    @Test
-    public void testConvert() {
-
-        StringArrayToStringConverter converter = new StringArrayToStringConverter();
-
-        String value = converter.convert(new String[]{"Hello", "World"});
-
-        Assert.assertEquals("Hello,World", value);
-
-        value = converter.convert(new String[]{});
-
-        Assert.assertNull(value);
-
-        value = converter.convert(null);
-
-        Assert.assertNull(value);
-
-    }
-
-}