From 4f3454002414f19ee07664c731a02aa30c4d8b27 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Tue, 20 Mar 2018 11:08:56 +0800 Subject: [PATCH 01/38] Manually merge pull request #1486, to make travis ci and codecov work after apache incubator transition. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f818df97a18..6a631991374 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Dubbo Project -[![Build Status](https://travis-ci.org/alibaba/dubbo.svg?branch=master)](https://travis-ci.org/alibaba/dubbo) -[![codecov](https://codecov.io/gh/alibaba/dubbo/branch/master/graph/badge.svg)](https://codecov.io/gh/alibaba/dubbo) +[![Build Status](https://travis-ci.org/apache/incubator-dubbo.svg?branch=master)](https://travis-ci.org/apache/incubator-dubbo) +[![codecov](https://codecov.io/gh/apache/incubator-dubbo/branch/master/graph/badge.svg)](https://codecov.io/gh/apache/incubator-dubbo) [![Gitter](https://badges.gitter.im/alibaba/dubbo.svg)](https://gitter.im/alibaba/dubbo?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) ![license](https://img.shields.io/github/license/alibaba/dubbo.svg) ![maven](https://img.shields.io/maven-central/v/com.alibaba/dubbo.svg) From 1e5b28f458ee5bb9ea3cb656fc5932e1296b3ee4 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 30 Mar 2018 23:33:37 +0800 Subject: [PATCH 02/38] Polish alibaba/dubbo#1306 --- .../AnnotationPropertyValuesAdapter.java | 92 ++++++++++ .../DubboConfigBindingBeanPostProcessor.java | 115 +++++++++++-- .../ReferenceAnnotationBeanPostProcessor.java | 161 +++++++++++++++--- .../annotation/ReferenceBeanBuilder.java | 26 ++- .../ServiceAnnotationBeanPostProcessor.java | 49 +++--- .../DubboConfigBindingRegistrar.java | 64 ++----- .../properties/AbstractDubboConfigBinder.java | 69 ++++++++ .../properties/DefaultDubboConfigBinder.java | 46 +++++ .../context/properties/DubboConfigBinder.java | 58 +++++++ .../converter/StringArrayToMapConverter.java | 38 +++++ .../StringArrayToStringConverter.java | 37 ++++ .../config/spring/util/AnnotationUtils.java | 89 ++++++++++ .../dubbo/config/spring/util/ObjectUtils.java | 37 ++++ .../spring/util/PropertySourcesUtils.java | 18 +- .../provider/AnnotationServiceImpl.java | 2 +- .../AnnotationPropertyValuesAdapterTest.java | 158 +++++++++++++++++ ...bboConfigBindingBeanPostProcessorTest.java | 66 +++++++ ...erenceAnnotationBeanPostProcessorTest.java | 95 +++++++++-- ...erviceAnnotationBeanPostProcessorTest.java | 3 +- .../DefaultDubboConfigBinderTest.java | 56 ++++++ .../StringArrayToMapConverterTest.java | 52 ++++++ .../StringArrayToStringConverterTest.java | 46 +++++ 22 files changed, 1241 insertions(+), 136 deletions(-) create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapter.java create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/AbstractDubboConfigBinder.java create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DubboConfigBinder.java create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToMapConverter.java create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToStringConverter.java create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotationUtils.java create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ObjectUtils.java create mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapterTest.java create mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java create mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinderTest.java create mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToMapConverterTest.java create mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToStringConverterTest.java diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapter.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapter.java new file mode 100644 index 00000000000..751399f8499 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapter.java @@ -0,0 +1,92 @@ +/* + * 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 org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.PropertyValues; +import org.springframework.core.env.PropertyResolver; + +import java.lang.annotation.Annotation; + +import static com.alibaba.dubbo.config.spring.util.AnnotationUtils.getAttributes; + +/** + * {@link Annotation} {@link PropertyValues} Adapter + * + * @see Annotation + * @see PropertyValues + * @since 2.5.11 + */ +class AnnotationPropertyValuesAdapter implements PropertyValues { + + private final Annotation annotation; + + private final PropertyResolver propertyResolver; + + private final boolean ignoreDefaultValue; + + private final PropertyValues delegate; + + public AnnotationPropertyValuesAdapter(Annotation annotation, PropertyResolver propertyResolver, boolean ignoreDefaultValue, String... ignoreAttributeNames) { + this.annotation = annotation; + this.propertyResolver = propertyResolver; + this.ignoreDefaultValue = ignoreDefaultValue; + this.delegate = adapt(annotation, ignoreDefaultValue, ignoreAttributeNames); + } + + public AnnotationPropertyValuesAdapter(Annotation annotation, PropertyResolver propertyResolver, String... ignoreAttributeNames) { + this(annotation, propertyResolver, true, ignoreAttributeNames); + } + + private PropertyValues adapt(Annotation annotation, boolean ignoreDefaultValue, String... ignoreAttributeNames) { + return new MutablePropertyValues(getAttributes(annotation, propertyResolver, ignoreDefaultValue, ignoreAttributeNames)); + } + + public Annotation getAnnotation() { + return annotation; + } + + public boolean isIgnoreDefaultValue() { + return ignoreDefaultValue; + } + + @Override + public PropertyValue[] getPropertyValues() { + return delegate.getPropertyValues(); + } + + @Override + public PropertyValue getPropertyValue(String propertyName) { + return delegate.getPropertyValue(propertyName); + } + + @Override + public PropertyValues changesSince(PropertyValues old) { + return delegate.changesSince(old); + } + + @Override + public boolean contains(String propertyName) { + return delegate.contains(propertyName); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java index 6899ad42fc1..6248ed32ffd 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java @@ -17,13 +17,25 @@ package com.alibaba.dubbo.config.spring.beans.factory.annotation; import com.alibaba.dubbo.common.utils.Assert; +import com.alibaba.dubbo.config.AbstractConfig; import com.alibaba.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar; import com.alibaba.dubbo.config.spring.context.annotation.EnableDubboConfigBinding; +import com.alibaba.dubbo.config.spring.context.properties.DefaultDubboConfigBinder; +import com.alibaba.dubbo.config.spring.context.properties.DubboConfigBinder; +import com.alibaba.dubbo.config.spring.util.BeanFactoryUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.beans.PropertyValues; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.EnvironmentAware; +import org.springframework.core.env.Environment; import org.springframework.validation.DataBinder; import java.util.Arrays; @@ -35,43 +47,52 @@ * @see DubboConfigBindingRegistrar * @since 2.5.8 */ -public class DubboConfigBindingBeanPostProcessor implements BeanPostProcessor { + +public class DubboConfigBindingBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware, InitializingBean { private final Log log = LogFactory.getLog(getClass()); /** - * Binding Bean Name + * The prefix of Configuration Properties */ - private final String beanName; + private final String prefix; /** - * Binding {@link PropertyValues} + * Binding Bean Name */ - private final PropertyValues propertyValues; + private final String beanName; + private DubboConfigBinder dubboConfigBinder; + + private ApplicationContext applicationContext; + + private boolean ignoreUnknownFields = true; + + private boolean ignoreInvalidFields = true; /** - * @param beanName Binding Bean Name - * @param propertyValues {@link PropertyValues} + * @param prefix the prefix of Configuration Properties + * @param beanName the binding Bean Name */ - public DubboConfigBindingBeanPostProcessor(String beanName, PropertyValues propertyValues) { + public DubboConfigBindingBeanPostProcessor(String prefix, String beanName) { + Assert.notNull(prefix, "The prefix of Configuration Properties must not be null"); Assert.notNull(beanName, "The name of bean must not be null"); - Assert.notNull(propertyValues, "The PropertyValues of bean must not be null"); + this.prefix = prefix; this.beanName = beanName; - this.propertyValues = propertyValues; } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - if (beanName.equals(this.beanName)) { - DataBinder dataBinder = new DataBinder(bean); - // TODO ignore invalid fields by annotation attribute - dataBinder.setIgnoreInvalidFields(true); - dataBinder.bind(propertyValues); + if (beanName.equals(this.beanName) && bean instanceof AbstractConfig) { + + AbstractConfig dubboConfig = (AbstractConfig) bean; + + dubboConfigBinder.bind(prefix, dubboConfig); + if (log.isInfoEnabled()) { - log.info("The properties of bean [name : " + beanName + "] have been binding by values : " - + Arrays.asList(propertyValues.getPropertyValues())); + log.info("The properties of bean [name : " + beanName + "] have been binding by prefix of " + + "configuration properties : " + prefix); } } @@ -79,10 +100,70 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro } + public boolean isIgnoreUnknownFields() { + return ignoreUnknownFields; + } + + public void setIgnoreUnknownFields(boolean ignoreUnknownFields) { + this.ignoreUnknownFields = ignoreUnknownFields; + } + + public boolean isIgnoreInvalidFields() { + return ignoreInvalidFields; + } + + public void setIgnoreInvalidFields(boolean ignoreInvalidFields) { + this.ignoreInvalidFields = ignoreInvalidFields; + } + + public DubboConfigBinder getDubboConfigBinder() { + return dubboConfigBinder; + } + + public void setDubboConfigBinder(DubboConfigBinder dubboConfigBinder) { + this.dubboConfigBinder = dubboConfigBinder; + } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @Override + public void afterPropertiesSet() throws Exception { + + if (dubboConfigBinder == null) { + try { + dubboConfigBinder = applicationContext.getBean(DubboConfigBinder.class); + } catch (BeansException ignored) { + if (log.isDebugEnabled()) { + log.debug("DubboConfigBinder Bean can't be found in ApplicationContext."); + } + // Use Default implementation + dubboConfigBinder = createDubboConfigBinder(applicationContext.getEnvironment()); + } + } + + dubboConfigBinder.setIgnoreUnknownFields(ignoreUnknownFields); + dubboConfigBinder.setIgnoreInvalidFields(ignoreInvalidFields); + + } + + /** + * Create {@link DubboConfigBinder} instance. + * + * @param environment + * @return {@link DefaultDubboConfigBinder} + */ + protected DubboConfigBinder createDubboConfigBinder(Environment environment) { + DefaultDubboConfigBinder defaultDubboConfigBinder = new DefaultDubboConfigBinder(); + defaultDubboConfigBinder.setEnvironment(environment); + return defaultDubboConfigBinder; + } + } 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 d8411de3640..31478f6cff7 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 @@ -33,6 +33,7 @@ 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; @@ -41,9 +42,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -73,8 +72,8 @@ public class ReferenceAnnotationBeanPostProcessor extends InstantiationAwareBean private ClassLoader classLoader; - private final ConcurrentMap injectionMetadataCache = - new ConcurrentHashMap(256); + private final ConcurrentMap injectionMetadataCache = + new ConcurrentHashMap(256); private final ConcurrentMap> referenceBeansCache = new ConcurrentHashMap>(); @@ -101,9 +100,9 @@ public PropertyValues postProcessPropertyValues( * @param beanClass The {@link Class} of Bean * @return non-null {@link List} */ - private List findFieldReferenceMetadata(final Class beanClass) { + private List findFieldReferenceMetadata(final Class beanClass) { - final List elements = new LinkedList(); + final List elements = new LinkedList(); ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() { @Override @@ -136,9 +135,9 @@ public void doWith(Field field) throws IllegalArgumentException, IllegalAccessEx * @param beanClass The {@link Class} of Bean * @return non-null {@link List} */ - private List findMethodReferenceMetadata(final Class beanClass) { + private List findMethodReferenceMetadata(final Class beanClass) { - final List elements = new LinkedList(); + final List elements = new LinkedList(); ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() { @Override @@ -180,15 +179,10 @@ public void doWith(Method method) throws IllegalArgumentException, IllegalAccess * @param beanClass * @return */ - private InjectionMetadata buildReferenceMetadata(final Class beanClass) { - - final List elements = new LinkedList(); - - elements.addAll(findFieldReferenceMetadata(beanClass)); - - elements.addAll(findMethodReferenceMetadata(beanClass)); - - return new InjectionMetadata(beanClass, elements); + private ReferenceInjectionMetadata buildReferenceMetadata(final Class beanClass) { + Collection fieldElements = findFieldReferenceMetadata(beanClass); + Collection methodElements = findMethodReferenceMetadata(beanClass); + return new ReferenceInjectionMetadata(beanClass, fieldElements, methodElements); } @@ -196,7 +190,7 @@ private InjectionMetadata findReferenceMetadata(String beanName, Class clazz, // 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. - InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); + ReferenceInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { synchronized (this.injectionMetadataCache) { metadata = this.injectionMetadataCache.get(cacheKey); @@ -270,6 +264,43 @@ public Collection> getReferenceBeans() { return this.referenceBeansCache.values(); } + + /** + * {@link Reference} {@link InjectionMetadata} implementation + * + * @since 2.5.11 + */ + private static class ReferenceInjectionMetadata extends InjectionMetadata { + + private final Collection fieldElements; + + private final Collection methodElements; + + + public ReferenceInjectionMetadata(Class targetClass, Collection fieldElements, + Collection methodElements) { + super(targetClass, combine(fieldElements, methodElements)); + this.fieldElements = fieldElements; + this.methodElements = methodElements; + } + + private static Collection combine(Collection... elements) { + List allElements = new ArrayList(); + for (Collection e : elements) { + allElements.addAll(e); + } + return allElements; + } + + public Collection getFieldElements() { + return fieldElements; + } + + public Collection getMethodElements() { + return methodElements; + } + } + /** * {@link Reference} {@link Method} {@link InjectionMetadata.InjectedElement} */ @@ -279,6 +310,8 @@ private class ReferenceMethodElement extends InjectionMetadata.InjectedElement { private final Reference reference; + private volatile ReferenceBean referenceBean; + protected ReferenceMethodElement(Method method, PropertyDescriptor pd, Reference reference) { super(method, pd); this.method = method; @@ -290,11 +323,11 @@ protected void inject(Object bean, String beanName, PropertyValues pvs) throws T Class referenceClass = pd.getPropertyType(); - Object referenceBean = buildReferenceBean(reference, referenceClass); + referenceBean = buildReferenceBean(reference, referenceClass); ReflectionUtils.makeAccessible(method); - method.invoke(bean, referenceBean); + method.invoke(bean, referenceBean.getObject()); } @@ -309,6 +342,8 @@ private class ReferenceFieldElement extends InjectionMetadata.InjectedElement { private final Reference reference; + private volatile ReferenceBean referenceBean; + protected ReferenceFieldElement(Field field, Reference reference) { super(field, null); this.field = field; @@ -320,17 +355,17 @@ protected void inject(Object bean, String beanName, PropertyValues pvs) throws T Class referenceClass = field.getType(); - Object referenceBean = buildReferenceBean(reference, referenceClass); + referenceBean = buildReferenceBean(reference, referenceClass); ReflectionUtils.makeAccessible(field); - field.set(bean, referenceBean); + field.set(bean, referenceBean.getObject()); } } - private Object buildReferenceBean(Reference reference, Class referenceClass) throws Exception { + private ReferenceBean buildReferenceBean(Reference reference, Class referenceClass) throws Exception { String referenceBeanCacheKey = generateReferenceBeanCacheKey(reference, referenceClass); @@ -348,8 +383,8 @@ private Object buildReferenceBean(Reference reference, Class referenceClass) } + return referenceBean; - return referenceBean.get(); } @@ -360,11 +395,17 @@ private Object buildReferenceBean(Reference reference, Class referenceClass) * @param beanClass {@link Class} * @return */ - private static String generateReferenceBeanCacheKey(Reference reference, Class beanClass) { + private String generateReferenceBeanCacheKey(Reference reference, Class beanClass) { String interfaceName = resolveInterfaceName(reference, beanClass); - String key = reference.group() + "/" + interfaceName + ":" + reference.version(); + String key = reference.url() + "/" + interfaceName + + "/" + reference.version() + + "/" + reference.group(); + + Environment environment = applicationContext.getEnvironment(); + + key = environment.resolvePlaceholders(key); return key; @@ -390,4 +431,70 @@ private static String resolveInterfaceName(Reference reference, Class beanCla } + + /** + * Get {@link ReferenceBean} {@link Map} in injected field. + * + * @return non-null {@link Map} + * @since 2.5.11 + */ + public Map> getInjectedFieldReferenceBeanMap() { + + Map> injectedElementReferenceBeanMap = + new LinkedHashMap>(); + + for (ReferenceInjectionMetadata metadata : injectionMetadataCache.values()) { + + Collection fieldElements = metadata.getFieldElements(); + + for (ReferenceFieldElement fieldElement : fieldElements) { + + injectedElementReferenceBeanMap.put(fieldElement, fieldElement.referenceBean); + + } + + } + + return injectedElementReferenceBeanMap; + + } + + /** + * Get {@link ReferenceBean} {@link Map} in injected method. + * + * @return non-null {@link Map} + * @since 2.5.11 + */ + public Map> getInjectedMethodReferenceBeanMap() { + + Map> injectedElementReferenceBeanMap = + new LinkedHashMap>(); + + for (ReferenceInjectionMetadata metadata : injectionMetadataCache.values()) { + + Collection methodElements = metadata.getMethodElements(); + + for (ReferenceMethodElement methodElement : methodElements) { + + injectedElementReferenceBeanMap.put(methodElement, methodElement.referenceBean); + + } + + } + + return injectedElementReferenceBeanMap; + + } + + private T getFieldValue(Object object, String fieldName, Class fieldType) { + + Field field = ReflectionUtils.findField(object.getClass(), fieldName, fieldType); + + ReflectionUtils.makeAccessible(field); + + return (T) ReflectionUtils.getField(field, object); + + } + + } 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 d2cc56d2bf0..5d9418fbc8a 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 @@ -19,12 +19,18 @@ 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.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 static com.alibaba.dubbo.config.spring.util.BeanFactoryUtils.getOptionalBean; +import static com.alibaba.dubbo.config.spring.util.ObjectUtils.of; /** * {@link ReferenceBean} Builder @@ -80,14 +86,30 @@ private void configureConsumerConfig(Reference reference, ReferenceBean refer @Override protected ReferenceBean doBuild() { - return new ReferenceBean(annotation); + return new ReferenceBean(); } @Override - protected void preConfigureBean(Reference annotation, ReferenceBean bean) { + 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); + // Bind annotation attributes + dataBinder.bind(new AnnotationPropertyValuesAdapter(reference, applicationContext.getEnvironment(), ignoreAttributeNames)); } + private ConversionService getConversionService() { + DefaultConversionService conversionService = new DefaultConversionService(); + conversionService.addConverter(new StringArrayToStringConverter()); + conversionService.addConverter(new StringArrayToMapConverter()); + return conversionService; + } + + @Override protected String resolveModuleConfigBeanName(Reference annotation) { return annotation.module(); 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 1d273451bfc..207b3f7d03d 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 @@ -21,20 +21,11 @@ import com.alibaba.dubbo.config.annotation.Service; import com.alibaba.dubbo.config.spring.ServiceBean; import com.alibaba.dubbo.config.spring.context.annotation.DubboClassPathBeanDefinitionScanner; - import org.springframework.beans.BeansException; +import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.beans.factory.config.SingletonBeanRegistry; -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; -import org.springframework.beans.factory.support.BeanNameGenerator; -import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.config.*; +import org.springframework.beans.factory.support.*; import org.springframework.context.EnvironmentAware; import org.springframework.context.ResourceLoaderAware; import org.springframework.context.annotation.AnnotationBeanNameGenerator; @@ -44,18 +35,11 @@ import org.springframework.core.env.Environment; import org.springframework.core.io.ResourceLoader; import org.springframework.core.type.filter.AnnotationTypeFilter; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.util.CollectionUtils; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; - -import java.util.Arrays; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; +import org.springframework.util.*; + +import java.util.*; +import static com.alibaba.dubbo.config.spring.util.ObjectUtils.of; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; import static org.springframework.context.annotation.AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR; import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; @@ -356,11 +340,20 @@ private Set resolvePackagesToScan(Set packagesToScan) { private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class interfaceClass, String annotatedServiceBeanName) { - BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class) - .addConstructorArgValue(service) - // References "ref" property to annotated-@Service Bean - .addPropertyReference("ref", annotatedServiceBeanName) - .addPropertyValue("interface", interfaceClass.getName()); + BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class); + + AbstractBeanDefinition beanDefinition = builder.getBeanDefinition(); + + MutablePropertyValues propertyValues = beanDefinition.getPropertyValues(); + + String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol", "interface"); + + propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(service, environment, ignoreAttributeNames)); + + // References "ref" property to annotated-@Service Bean + addPropertyReference(builder, "ref", annotatedServiceBeanName); + // Set interface + builder.addPropertyValue("interface", interfaceClass.getName()); /** * Add {@link com.alibaba.dubbo.config.ProviderConfig} Bean reference diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java index cd9cadd3e7b..452d9d3a236 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java @@ -20,8 +20,6 @@ import com.alibaba.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.beans.MutablePropertyValues; -import org.springframework.beans.PropertyValues; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -30,15 +28,21 @@ import org.springframework.context.EnvironmentAware; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.annotation.AnnotationAttributes; -import org.springframework.core.env.*; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; +import org.springframework.core.env.PropertySources; import org.springframework.core.type.AnnotationMetadata; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; -import java.util.*; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties; +import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.normalizePrefix; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; import static org.springframework.beans.factory.support.BeanDefinitionReaderUtils.registerWithGeneratedName; @@ -82,9 +86,7 @@ private void registerDubboConfigBeans(String prefix, boolean multiple, BeanDefinitionRegistry registry) { - PropertySources propertySources = environment.getPropertySources(); - - Map properties = getSubProperties(propertySources, prefix); + Map properties = getSubProperties(environment.getPropertySources(), prefix); if (CollectionUtils.isEmpty(properties)) { if (log.isDebugEnabled()) { @@ -94,16 +96,14 @@ private void registerDubboConfigBeans(String prefix, return; } - Set beanNames = multiple ? resolveMultipleBeanNames(prefix, properties) : - Collections.singleton(resolveSingleBeanName(configClass, properties, registry)); + Set beanNames = multiple ? resolveMultipleBeanNames(properties) : + Collections.singleton(resolveSingleBeanName(properties, configClass, registry)); for (String beanName : beanNames) { registerDubboConfigBean(beanName, configClass, registry); - MutablePropertyValues propertyValues = resolveBeanPropertyValues(beanName, multiple, properties); - - registerDubboConfigBindingBeanPostProcessor(beanName, propertyValues, registry); + registerDubboConfigBindingBeanPostProcessor(prefix, beanName, multiple, registry); } @@ -125,14 +125,16 @@ private void registerDubboConfigBean(String beanName, Class processorClass = DubboConfigBindingBeanPostProcessor.class; BeanDefinitionBuilder builder = rootBeanDefinition(processorClass); - builder.addConstructorArgValue(beanName).addConstructorArgValue(propertyValues); + String actualPrefix = multiple ? normalizePrefix(prefix) + beanName : prefix; + + builder.addConstructorArgValue(actualPrefix).addConstructorArgValue(beanName); AbstractBeanDefinition beanDefinition = builder.getBeanDefinition(); @@ -147,36 +149,6 @@ private void registerDubboConfigBindingBeanPostProcessor(String beanName, Proper } - private MutablePropertyValues resolveBeanPropertyValues(String beanName, boolean multiple, - Map properties) { - - MutablePropertyValues propertyValues = new MutablePropertyValues(); - - if (multiple) { // For Multiple Beans - - MutablePropertySources propertySources = new MutablePropertySources(); - propertySources.addFirst(new MapPropertySource(beanName, new TreeMap(properties))); - - Map subProperties = getSubProperties(propertySources, beanName); - - propertyValues.addPropertyValues(subProperties); - - - } else { // For Single Bean - - for (Map.Entry entry : properties.entrySet()) { - String propertyName = entry.getKey(); - if (!propertyName.contains(".")) { // ignore property name with "." - propertyValues.addPropertyValue(propertyName, entry.getValue()); - } - } - - } - - return propertyValues; - - } - @Override public void setEnvironment(Environment environment) { @@ -186,7 +158,7 @@ public void setEnvironment(Environment environment) { } - private Set resolveMultipleBeanNames(String prefix, Map properties) { + private Set resolveMultipleBeanNames(Map properties) { Set beanNames = new LinkedHashSet(); @@ -207,7 +179,7 @@ private Set resolveMultipleBeanNames(String prefix, Map } - private String resolveSingleBeanName(Class configClass, Map properties, + private String resolveSingleBeanName(Map properties, Class configClass, BeanDefinitionRegistry registry) { String beanName = properties.get("id"); diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/AbstractDubboConfigBinder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/AbstractDubboConfigBinder.java new file mode 100644 index 00000000000..b10336797f8 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/AbstractDubboConfigBinder.java @@ -0,0 +1,69 @@ +/* + * 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.properties; + +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; +import org.springframework.core.env.PropertySource; + +/** + * Abstract {@link DubboConfigBinder} implementation + */ +public abstract class AbstractDubboConfigBinder implements DubboConfigBinder { + + private Iterable> propertySources; + + private boolean ignoreUnknownFields = true; + + private boolean ignoreInvalidFields = false; + + /** + * Get multiple {@link PropertySource propertySources} + * + * @return multiple {@link PropertySource propertySources} + */ + protected Iterable> getPropertySources() { + return propertySources; + } + + public boolean isIgnoreUnknownFields() { + return ignoreUnknownFields; + } + + @Override + public void setIgnoreUnknownFields(boolean ignoreUnknownFields) { + this.ignoreUnknownFields = ignoreUnknownFields; + } + + public boolean isIgnoreInvalidFields() { + return ignoreInvalidFields; + } + + @Override + public void setIgnoreInvalidFields(boolean ignoreInvalidFields) { + this.ignoreInvalidFields = ignoreInvalidFields; + } + + @Override + public final void setEnvironment(Environment environment) { + + if (environment instanceof ConfigurableEnvironment) { + this.propertySources = ((ConfigurableEnvironment) environment).getPropertySources(); + } + + } +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java new file mode 100644 index 00000000000..52cc87ca4f5 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java @@ -0,0 +1,46 @@ +/* + * 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.properties; + +import com.alibaba.dubbo.config.AbstractConfig; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.validation.DataBinder; + +import java.util.Map; + +import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties; + +/** + * Default {@link DubboConfigBinder} implementation based on Spring {@link DataBinder} + */ +public class DefaultDubboConfigBinder extends AbstractDubboConfigBinder { + + @Override + public void bind(String prefix, C dubboConfig) { + DataBinder dataBinder = new DataBinder(dubboConfig); + // Set ignored* + dataBinder.setIgnoreInvalidFields(isIgnoreInvalidFields()); + dataBinder.setIgnoreUnknownFields(isIgnoreUnknownFields()); + // Get properties under specified prefix from PropertySources + Map properties = getSubProperties(getPropertySources(), prefix); + // Convert Map to MutablePropertyValues + MutablePropertyValues propertyValues = new MutablePropertyValues(properties); + // Bind + dataBinder.bind(propertyValues); + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DubboConfigBinder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DubboConfigBinder.java new file mode 100644 index 00000000000..c19fadce278 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DubboConfigBinder.java @@ -0,0 +1,58 @@ +/* + * 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.properties; + +import com.alibaba.dubbo.config.AbstractConfig; +import org.springframework.context.EnvironmentAware; + +/** + * {@link AbstractConfig DubboConfig} Binder + * + * @see AbstractConfig + * @see EnvironmentAware + * @since 2.5.11 + */ +public interface DubboConfigBinder extends EnvironmentAware { + + /** + * Set whether to ignore unknown fields, that is, whether to ignore bind + * parameters that do not have corresponding fields in the target object. + *

Default is "true". Turn this off to enforce that all bind parameters + * must have a matching field in the target object. + * + * @see #bind + */ + void setIgnoreUnknownFields(boolean ignoreUnknownFields); + + /** + * Set whether to ignore invalid fields, that is, whether to ignore bind + * parameters that have corresponding fields in the target object which are + * not accessible (for example because of null values in the nested path). + *

Default is "false". + * + * @see #bind + */ + void setIgnoreInvalidFields(boolean ignoreInvalidFields); + + /** + * Bind the properties to {@link C Dubbo Config} Object under specified prefix. + * + * @param prefix + * @param dubboConfig + */ + void bind(String prefix, C dubboConfig); +} 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 new file mode 100644 index 00000000000..56c6d4c4ccd --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToMapConverter.java @@ -0,0 +1,38 @@ +/* + * 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> { + + @Override + public Map 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 new file mode 100644 index 00000000000..23e948b0644 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToStringConverter.java @@ -0,0 +1,37 @@ +/* + * 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 { + + @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 new file mode 100644 index 00000000000..aa15e567eb0 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotationUtils.java @@ -0,0 +1,89 @@ +/* + * 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.util; + +import org.springframework.core.env.PropertyResolver; + +import java.lang.annotation.Annotation; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import static java.lang.String.valueOf; +import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes; +import static org.springframework.core.annotation.AnnotationUtils.getDefaultValue; +import static org.springframework.util.CollectionUtils.arrayToList; +import static org.springframework.util.ObjectUtils.nullSafeEquals; +import static org.springframework.util.StringUtils.trimAllWhitespace; + +/** + * Annotation Utilities Class + * + * @see org.springframework.core.annotation.AnnotationUtils + * @since 2.5.11 + */ +public class AnnotationUtils { + + /** + * Get {@link Annotation} attributes + * + * @param annotation + * @param propertyResolver + * @param ignoreDefaultValue + * @return non-null + */ + public static Map getAttributes(Annotation annotation, PropertyResolver propertyResolver, + boolean ignoreDefaultValue, String... ignoreAttributeNames) { + + Set ignoreAttributeNamesSet = new HashSet(arrayToList(ignoreAttributeNames)); + + Map attributes = getAnnotationAttributes(annotation); + + Map actualAttributes = new LinkedHashMap(); + + boolean requiredResolve = propertyResolver != null; + + for (Map.Entry entry : attributes.entrySet()) { + + String attributeName = entry.getKey(); + Object attributeValue = entry.getValue(); + + // ignore default attribute value + if (ignoreDefaultValue && nullSafeEquals(attributeValue, getDefaultValue(annotation, attributeName))) { + continue; + } + + // ignore attribute name + if (ignoreAttributeNamesSet.contains(attributeName)) { + continue; + } + + if (requiredResolve && attributeValue instanceof String) { // Resolve Placeholder + String resolvedValue = propertyResolver.resolvePlaceholders(valueOf(attributeValue)); + attributeValue = trimAllWhitespace(resolvedValue); + } + + actualAttributes.put(attributeName, attributeValue); + + } + + return actualAttributes; + + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ObjectUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ObjectUtils.java new file mode 100644 index 00000000000..00db1e770f5 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ObjectUtils.java @@ -0,0 +1,37 @@ +/* + * 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.util; + +/** + * Object Utilities Class + * + * @since 2.5.11 + */ +public class ObjectUtils { + + /** + * of factory method + * + * @param values + * @param + * @return + */ + public static T[] of(T... values) { + return values; + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java index fe1c61bbbde..5b183e1f2f7 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java @@ -35,16 +35,16 @@ public abstract class PropertySourcesUtils { /** * Get Sub {@link Properties} * - * @param propertySources {@link PropertySources} + * @param propertySources {@link PropertySource} Iterable * @param prefix the prefix of property name - * @return Map + * @return Map * @see Properties */ - public static Map getSubProperties(PropertySources propertySources, String prefix) { + public static Map getSubProperties(Iterable> propertySources, String prefix) { Map subProperties = new LinkedHashMap(); - String normalizedPrefix = prefix.endsWith(".") ? prefix : prefix + "."; + String normalizedPrefix = normalizePrefix(prefix); for (PropertySource source : propertySources) { if (source instanceof EnumerablePropertySource) { @@ -62,4 +62,14 @@ public static Map getSubProperties(PropertySources propertySourc } + /** + * Normalize the prefix + * + * @param prefix the prefix + * @return the prefix + */ + public static String normalizePrefix(String prefix) { + return prefix.endsWith(".") ? prefix : prefix + "."; + } + } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/annotation/provider/AnnotationServiceImpl.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/annotation/provider/AnnotationServiceImpl.java index 7766a1a6025..327f4d91bac 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/annotation/provider/AnnotationServiceImpl.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/annotation/provider/AnnotationServiceImpl.java @@ -23,7 +23,7 @@ /** * DemoServiceImpl */ -@Service(version = "1.2") +@Service(version = "${provider.version}") public class AnnotationServiceImpl implements DemoService { public String sayName(String name) { diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapterTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapterTest.java new file mode 100644 index 00000000000..36def719d36 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapterTest.java @@ -0,0 +1,158 @@ +/* + * 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.common.utils.CollectionUtils; +import com.alibaba.dubbo.config.annotation.Reference; +import com.alibaba.dubbo.config.spring.ReferenceBean; +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.core.convert.converter.Converter; +import org.springframework.core.convert.support.DefaultConversionService; +import org.springframework.mock.env.MockEnvironment; +import org.springframework.util.ReflectionUtils; +import org.springframework.validation.DataBinder; + +import java.lang.reflect.Field; +import java.util.LinkedHashMap; +import java.util.Map; + +import static org.springframework.util.StringUtils.arrayToCommaDelimitedString; + +/** + * {@link AnnotationPropertyValuesAdapter} Test + * + * @since 2.5.11 + */ +public class AnnotationPropertyValuesAdapterTest { + + @Test + public void test() { + + MockEnvironment mockEnvironment = new MockEnvironment(); + + mockEnvironment.setProperty("version", "1.0.0"); + + mockEnvironment.setProperty("url", " dubbo://localhost:12345"); + + Field field = ReflectionUtils.findField(TestBean.class, "demoService"); + + Reference reference = AnnotationUtils.getAnnotation(field, Reference.class); + + AnnotationPropertyValuesAdapter propertyValues = new AnnotationPropertyValuesAdapter(reference, mockEnvironment); + + ReferenceBean referenceBean = new ReferenceBean(); + + DataBinder dataBinder = new DataBinder(referenceBean); + + dataBinder.setDisallowedFields("application", "module", "consumer", "monitor", "registry"); + + DefaultConversionService conversionService = new DefaultConversionService(); + + conversionService.addConverter(new Converter() { + @Override + public String convert(String[] source) { + return arrayToCommaDelimitedString(source); + } + }); + + conversionService.addConverter(new Converter>() { + @Override + public Map convert(String[] source) { + return CollectionUtils.toStringMap(source); + } + }); + + + dataBinder.setConversionService(conversionService); + + + dataBinder.bind(propertyValues); + +// System.out.println(referenceBean); + + Assert.assertEquals(DemoService.class, referenceBean.getInterfaceClass()); + Assert.assertEquals("com.alibaba.dubbo.config.spring.api.DemoService", referenceBean.getInterface()); + Assert.assertEquals("1.0.0", referenceBean.getVersion()); + Assert.assertEquals("group", referenceBean.getGroup()); + Assert.assertEquals("dubbo://localhost:12345", referenceBean.getUrl()); + Assert.assertEquals("client", referenceBean.getClient()); + Assert.assertEquals(true, referenceBean.isGeneric()); + Assert.assertEquals(true, referenceBean.isInjvm()); + Assert.assertEquals(false, referenceBean.isCheck()); + Assert.assertEquals(true, referenceBean.isInit()); + Assert.assertEquals(true, referenceBean.getLazy()); + Assert.assertEquals(true, referenceBean.getStubevent()); + Assert.assertEquals("reconnect", referenceBean.getReconnect()); + Assert.assertEquals(true, referenceBean.getSticky()); + + Assert.assertEquals("javassist", referenceBean.getProxy()); + + Assert.assertEquals("stub", referenceBean.getStub()); + Assert.assertEquals("failover", referenceBean.getCluster()); + Assert.assertEquals(Integer.valueOf(1), referenceBean.getConnections()); + Assert.assertEquals(Integer.valueOf(1), referenceBean.getCallbacks()); + Assert.assertEquals("onconnect", referenceBean.getOnconnect()); + Assert.assertEquals("ondisconnect", referenceBean.getOndisconnect()); + Assert.assertEquals("owner", referenceBean.getOwner()); + Assert.assertEquals("layer", referenceBean.getLayer()); + Assert.assertEquals(Integer.valueOf(2), referenceBean.getRetries()); + Assert.assertEquals("random", referenceBean.getLoadbalance()); + Assert.assertEquals(true, referenceBean.isAsync()); + Assert.assertEquals(Integer.valueOf(1), referenceBean.getActives()); + Assert.assertEquals(true, referenceBean.getSent()); + Assert.assertEquals("mock", referenceBean.getMock()); + Assert.assertEquals("validation", referenceBean.getValidation()); + Assert.assertEquals(Integer.valueOf(2), referenceBean.getTimeout()); + Assert.assertEquals("cache", referenceBean.getCache()); + Assert.assertEquals("default,default", referenceBean.getFilter()); + Assert.assertEquals("default,default", referenceBean.getListener()); + + Map data = new LinkedHashMap(); + data.put("key1", "value1"); + + Assert.assertEquals(data, referenceBean.getParameters()); + // Bean compare + Assert.assertEquals(null, referenceBean.getApplication()); + Assert.assertEquals(null, referenceBean.getModule()); + Assert.assertEquals(null, referenceBean.getConsumer()); + Assert.assertEquals(null, referenceBean.getMonitor()); + Assert.assertEquals(null, referenceBean.getRegistry()); + + } + + private static class TestBean { + + @Reference( + interfaceClass = DemoService.class, interfaceName = "com.alibaba.dubbo.config.spring.api.DemoService", version = "${version}", group = "group", + url = "${url} ", client = "client", generic = true, injvm = true, + check = false, init = true, lazy = true, stubevent = true, + reconnect = "reconnect", sticky = true, proxy = "javassist", stub = "stub", + cluster = "failover", connections = 1, callbacks = 1, onconnect = "onconnect", + ondisconnect = "ondisconnect", owner = "owner", layer = "layer", retries = 2, + loadbalance = "random", async = true, actives = 1, sent = true, + mock = "mock", validation = "validation", timeout = 2, cache = "cache", + filter = {"default", "default"}, listener = {"default", "default"}, parameters = {"key1", "value1"}, application = "application", + module = "module", consumer = "consumer", monitor = "monitor", registry = {"registry1", "registry2"} + ) + private DemoService demoService; + + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java new file mode 100644 index 00000000000..05a49807d4e --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java @@ -0,0 +1,66 @@ +/* + * 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.spring.context.properties.DefaultDubboConfigBinder; +import com.alibaba.dubbo.config.spring.context.properties.DubboConfigBinder; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; + +/** + * {@link DubboConfigBindingBeanPostProcessor} + */ +@PropertySource({"classpath:/META-INF/config.properties"}) +@Configuration +public class DubboConfigBindingBeanPostProcessorTest { + + @Bean("applicationBean") + public ApplicationConfig applicationConfig() { + return new ApplicationConfig(); + } + + @Bean + public DubboConfigBinder dubboConfigBinder() { + return new DefaultDubboConfigBinder(); + } + + @Test + public void test() { + + final AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); + + applicationContext.register(getClass()); + + Class processorClass = DubboConfigBindingBeanPostProcessor.class; + + applicationContext.registerBeanDefinition("DubboConfigBindingBeanPostProcessor", rootBeanDefinition(processorClass).addConstructorArgValue("dubbo.application").addConstructorArgValue("applicationBean").getBeanDefinition()); + + applicationContext.refresh(); + + ApplicationConfig applicationConfig = applicationContext.getBean(ApplicationConfig.class); + + Assert.assertEquals("dubbo-demo-application", applicationConfig.getName()); + + } +} 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 3f9a50e1af2..5f334914d3e 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 @@ -20,16 +20,16 @@ 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.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.*; 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.support.ClassPathXmlApplicationContext; import java.util.Collection; +import java.util.Map; import static com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor.BEAN_NAME; @@ -40,12 +40,27 @@ */ public class ReferenceAnnotationBeanPostProcessorTest { - private static final String PROVIDER_LOCATION = "META-INF/spring/dubbo-provider.xml"; + 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"); + } @Before - public void before() { + public void init() { // Starts Provider - new ClassPathXmlApplicationContext(PROVIDER_LOCATION); + providerApplicationContext = new AnnotationConfigApplicationContext(ServiceAnnotationBeanPostProcessorTest.TestConfiguration.class); + } + + @After + public void destroy() { + // Shutdowns Provider + providerApplicationContext.close(); } @Test @@ -95,6 +110,66 @@ public void testGetReferenceBeans() { } + @Test + public void testGetInjectedFieldReferenceBeanMap() { + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); + + ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME, + ReferenceAnnotationBeanPostProcessor.class); + + + Map> referenceBeanMap = + beanPostProcessor.getInjectedFieldReferenceBeanMap(); + + Assert.assertEquals(1, referenceBeanMap.size()); + + for (Map.Entry> entry : referenceBeanMap.entrySet()) { + + InjectionMetadata.InjectedElement injectedElement = entry.getKey(); + + Assert.assertEquals("com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor$ReferenceFieldElement", + injectedElement.getClass().getName()); + + ReferenceBean referenceBean = entry.getValue(); + + Assert.assertEquals("1.2", referenceBean.getVersion()); + Assert.assertEquals("dubbo://127.0.0.1:12345", referenceBean.getUrl()); + + } + + } + + @Test + public void testGetInjectedMethodReferenceBeanMap() { + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); + + ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME, + ReferenceAnnotationBeanPostProcessor.class); + + + Map> referenceBeanMap = + beanPostProcessor.getInjectedMethodReferenceBeanMap(); + + Assert.assertEquals(2, referenceBeanMap.size()); + + for (Map.Entry> entry : referenceBeanMap.entrySet()) { + + InjectionMetadata.InjectedElement injectedElement = entry.getKey(); + + Assert.assertEquals("com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor$ReferenceMethodElement", + injectedElement.getClass().getName()); + + ReferenceBean referenceBean = entry.getValue(); + + Assert.assertEquals("1.2", referenceBean.getVersion()); + Assert.assertEquals("dubbo://127.0.0.1:12345", referenceBean.getUrl()); + + } + + } + private static class AncestorBean { @@ -121,7 +196,7 @@ public ApplicationContext getApplicationContext() { private static class ParentBean extends AncestorBean { - @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345") + @Reference(version = "${consumer.version}", url = "${consumer.url}") private DemoService demoServiceFromParent; public DemoService getDemoServiceFromParent() { @@ -133,7 +208,7 @@ public DemoService getDemoServiceFromParent() { @ImportResource("META-INF/spring/dubbo-annotation-consumer.xml") @DubboComponentScan(basePackageClasses = ReferenceAnnotationBeanPostProcessorTest.class) - private static class TestBean extends ParentBean { + static class TestBean extends ParentBean { private DemoService demoService; @@ -150,4 +225,4 @@ public void setDemoService(DemoService demoService) { } } -} +} \ 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/ServiceAnnotationBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessorTest.java index e5714c7f254..c0964418144 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 @@ -44,7 +44,8 @@ classes = {ServiceAnnotationBeanPostProcessorTest.TestConfiguration.class}) @TestPropertySource(properties = { "package1 = com.alibaba.dubbo.config.spring.context.annotation", - "packagesToScan = ${package1}" + "packagesToScan = ${package1}", + "provider.version = 1.2" }) public class ServiceAnnotationBeanPostProcessorTest { diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinderTest.java new file mode 100644 index 00000000000..f0ec69f505b --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinderTest.java @@ -0,0 +1,56 @@ +/* + * 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.properties; + + +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.ProtocolConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@TestPropertySource(locations = "classpath:/dubbo.properties") +@ContextConfiguration(classes = DefaultDubboConfigBinder.class) +public class DefaultDubboConfigBinderTest { + + @Autowired + private DubboConfigBinder dubboConfigBinder; + + @Test + public void testBinder() { + + ApplicationConfig applicationConfig = new ApplicationConfig(); + dubboConfigBinder.bind("dubbo.application", applicationConfig); + Assert.assertEquals("hello", applicationConfig.getName()); + Assert.assertEquals("world", applicationConfig.getOwner()); + + RegistryConfig registryConfig = new RegistryConfig(); + dubboConfigBinder.bind("dubbo.registry", registryConfig); + Assert.assertEquals("10.20.153.17", registryConfig.getAddress()); + + ProtocolConfig protocolConfig = new ProtocolConfig(); + dubboConfigBinder.bind("dubbo.protocol", protocolConfig); + Assert.assertEquals(Integer.valueOf(20881), protocolConfig.getPort()); + + } +} 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 new file mode 100644 index 00000000000..51be7c3f2f2 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToMapConverterTest.java @@ -0,0 +1,52 @@ +/* + * 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 value = converter.convert(new String[]{"Hello", "World"}); + + Map expected = new LinkedHashMap(); + + 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 new file mode 100644 index 00000000000..67e82479235 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToStringConverterTest.java @@ -0,0 +1,46 @@ +/* + * 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); + + } + +} From 93591f056dafca5f910f8ae679820793561a5fd1 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Sun, 15 Apr 2018 14:32:46 +0800 Subject: [PATCH 03/38] Optimize imports --- .../context/annotation/DubboConfigBindingRegistrar.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java index 1fcaf38db69..6936787cc67 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java @@ -30,9 +30,6 @@ import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; -import org.springframework.core.env.MapPropertySource; -import org.springframework.core.env.MutablePropertySources; -import org.springframework.core.env.PropertySources; import org.springframework.core.type.AnnotationMetadata; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -43,8 +40,6 @@ import java.util.Map; import java.util.Set; -import java.util.TreeMap; - import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties; import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.normalizePrefix; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; From d57343e4a4f228cf02bbf0a3b8c33883082e1d98 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Sun, 15 Apr 2018 15:44:59 +0800 Subject: [PATCH 04/38] Optimize imports --- .../dubbo/config/spring/ReferenceBean.java | 1 - .../dubbo/config/spring/ServiceBean.java | 1 - .../DubboConfigBindingBeanPostProcessor.java | 9 ------- .../ReferenceAnnotationBeanPostProcessor.java | 7 ++++- .../ServiceAnnotationBeanPostProcessor.java | 27 +++++++++++++++---- .../dubbo/config/spring/ConfigTest.java | 15 +++++++++-- ...erenceAnnotationBeanPostProcessorTest.java | 6 ++++- .../annotation/EnableDubboConfigTest.java | 8 +++++- .../context/annotation/EnableDubboTest.java | 6 ++++- .../config/spring/filter/MockFilter.java | 7 ++++- 10 files changed, 64 insertions(+), 23 deletions(-) diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/ReferenceBean.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/ReferenceBean.java index f3aa9b02493..a9d5b3f58cb 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/ReferenceBean.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/ReferenceBean.java @@ -25,7 +25,6 @@ import com.alibaba.dubbo.config.annotation.Reference; import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory; import com.alibaba.dubbo.config.support.Parameter; - import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; 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 2e614efdb69..c4eb0c28213 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 @@ -25,7 +25,6 @@ import com.alibaba.dubbo.config.ServiceConfig; import com.alibaba.dubbo.config.annotation.Service; 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; diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java index 6248ed32ffd..cbb5435d33f 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java @@ -22,23 +22,14 @@ import com.alibaba.dubbo.config.spring.context.annotation.EnableDubboConfigBinding; import com.alibaba.dubbo.config.spring.context.properties.DefaultDubboConfigBinder; import com.alibaba.dubbo.config.spring.context.properties.DubboConfigBinder; -import com.alibaba.dubbo.config.spring.util.BeanFactoryUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; -import org.springframework.beans.PropertyValues; import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; -import org.springframework.context.EnvironmentAware; import org.springframework.core.env.Environment; -import org.springframework.validation.DataBinder; - -import java.util.Arrays; /** * Dubbo Config Binding {@link BeanPostProcessor} 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 31478f6cff7..cfd719668ae 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 @@ -42,7 +42,12 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; 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 207b3f7d03d..af05aac1383 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 @@ -24,8 +24,17 @@ import org.springframework.beans.BeansException; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.factory.config.*; -import org.springframework.beans.factory.support.*; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.config.SingletonBeanRegistry; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; +import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.beans.factory.support.ManagedList; import org.springframework.context.EnvironmentAware; import org.springframework.context.ResourceLoaderAware; import org.springframework.context.annotation.AnnotationBeanNameGenerator; @@ -35,9 +44,17 @@ import org.springframework.core.env.Environment; import org.springframework.core.io.ResourceLoader; import org.springframework.core.type.filter.AnnotationTypeFilter; -import org.springframework.util.*; - -import java.util.*; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; import static com.alibaba.dubbo.config.spring.util.ObjectUtils.of; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/ConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/ConfigTest.java index 3b54e9d8a5a..80de429007e 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/ConfigTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/ConfigTest.java @@ -21,7 +21,13 @@ import com.alibaba.dubbo.common.extension.ExtensionLoader; import com.alibaba.dubbo.common.utils.NetUtils; import com.alibaba.dubbo.common.utils.StringUtils; -import com.alibaba.dubbo.config.*; +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.ConsumerConfig; +import com.alibaba.dubbo.config.ProtocolConfig; +import com.alibaba.dubbo.config.ProviderConfig; +import com.alibaba.dubbo.config.ReferenceConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.config.ServiceConfig; import com.alibaba.dubbo.config.spring.action.DemoActionByAnnotation; import com.alibaba.dubbo.config.spring.action.DemoActionBySetter; import com.alibaba.dubbo.config.spring.annotation.consumer.AnnotationAction; @@ -49,7 +55,12 @@ import java.util.Collection; import java.util.List; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.junit.matchers.JUnitMatchers.containsString; 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 5f334914d3e..01dbc5317d0 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 @@ -20,7 +20,11 @@ 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.*; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.InjectionMetadata; import org.springframework.context.ApplicationContext; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java index 13f733da9b8..1673be10ce7 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java @@ -16,7 +16,13 @@ */ package com.alibaba.dubbo.config.spring.context.annotation; -import com.alibaba.dubbo.config.*; +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.ConsumerConfig; +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 org.junit.Assert; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboTest.java index 2020bed667e..c5018da2522 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboTest.java @@ -24,7 +24,11 @@ import org.junit.Assert; import org.junit.Test; import org.springframework.aop.support.AopUtils; -import org.springframework.context.annotation.*; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +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; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/filter/MockFilter.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/filter/MockFilter.java index de192b92e1f..e4fc142a7c9 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/filter/MockFilter.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/filter/MockFilter.java @@ -16,7 +16,12 @@ */ package com.alibaba.dubbo.config.spring.filter; -import com.alibaba.dubbo.rpc.*; +import com.alibaba.dubbo.rpc.Filter; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.Protocol; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.cluster.LoadBalance; /** From d428f5fba767fbe6b7e62278eb27ae01407db9b6 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Mon, 23 Apr 2018 10:14:13 +0800 Subject: [PATCH 05/38] Remove invalid JavaDoc --- .../config/spring/context/properties/DubboConfigBinder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DubboConfigBinder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DubboConfigBinder.java index c19fadce278..6ebb86296d5 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DubboConfigBinder.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DubboConfigBinder.java @@ -49,7 +49,7 @@ public interface DubboConfigBinder extends EnvironmentAware { void setIgnoreInvalidFields(boolean ignoreInvalidFields); /** - * Bind the properties to {@link C Dubbo Config} Object under specified prefix. + * Bind the properties to Dubbo Config Object under specified prefix. * * @param prefix * @param dubboConfig From 5d72ddf8eccf48b35cdd9956811a8aeb2986c7d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=A9=AC=E5=93=A5?= Date: Mon, 23 Apr 2018 10:16:47 +0800 Subject: [PATCH 06/38] Update DubboConfigBinder.java Remove invalid JavaDoc --- .../config/spring/context/properties/DubboConfigBinder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DubboConfigBinder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DubboConfigBinder.java index c19fadce278..6ebb86296d5 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DubboConfigBinder.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DubboConfigBinder.java @@ -49,7 +49,7 @@ public interface DubboConfigBinder extends EnvironmentAware { void setIgnoreInvalidFields(boolean ignoreInvalidFields); /** - * Bind the properties to {@link C Dubbo Config} Object under specified prefix. + * Bind the properties to Dubbo Config Object under specified prefix. * * @param prefix * @param dubboConfig From 5bab1417d85ae63485ee6656baa3fef3a52e1f33 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Mon, 23 Apr 2018 21:44:01 +0800 Subject: [PATCH 07/38] Fix apache/incubator-dubbo#1653 --- .../ServiceAnnotationBeanPostProcessor.java | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) 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 6e7fe03b1a4..35604650906 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,6 +71,8 @@ public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, ResourceLoaderAware, BeanClassLoaderAware { + private static final String SEPARATOR = ":"; + private final Logger logger = LoggerFactory.getLogger(getClass()); private final Set packagesToScan; @@ -254,7 +256,7 @@ private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, Bean buildServiceBeanDefinition(service, interfaceClass, annotatedServiceBeanName); // ServiceBean Bean name - String beanName = generateServiceBeanName(interfaceClass, annotatedServiceBeanName); + String beanName = generateServiceBeanName(service, interfaceClass, annotatedServiceBeanName); if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean registry.registerBeanDefinition(beanName, serviceBeanDefinition); @@ -279,14 +281,35 @@ private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, Bean /** * Generates the bean name of {@link ServiceBean} * + * @param service * @param interfaceClass the class of interface annotated {@link Service} * @param annotatedServiceBeanName the bean name of annotated {@link Service} * @return ServiceBean@interfaceClassName#annotatedServiceBeanName * @since 2.5.9 */ - private String generateServiceBeanName(Class interfaceClass, String annotatedServiceBeanName) { + private String generateServiceBeanName(Service service, Class interfaceClass, String annotatedServiceBeanName) { + + StringBuilder beanNameBuilder = new StringBuilder(ServiceBean.class.getSimpleName()); + + 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 "ServiceBean@" + interfaceClass.getName() + "#" + annotatedServiceBeanName; + return beanNameBuilder.toString(); } @@ -477,4 +500,4 @@ public void setBeanClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; } -} +} \ No newline at end of file From 31acca8845dce62ba611afde15fc20b75a41a0a3 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Thu, 10 May 2018 17:32:50 +0800 Subject: [PATCH 08/38] Fixed apache/incubator-dubbo#1772 --- .../config/spring/util/PropertySourcesUtils.java | 6 ++++-- .../config/spring/util/PropertySourcesUtilsTest.java | 12 +++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java index 5b183e1f2f7..a84e18ac819 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java @@ -51,8 +51,10 @@ public static Map getSubProperties(Iterable> p for (String name : ((EnumerablePropertySource) source).getPropertyNames()) { if (name.startsWith(normalizedPrefix)) { String subName = name.substring(normalizedPrefix.length()); - Object value = source.getProperty(name); - subProperties.put(subName, String.valueOf(value)); + if (!subProperties.containsKey(subName)) { + Object value = source.getProperty(name); + subProperties.put(subName, String.valueOf(value)); + } } } } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java index 5dd526f7bcf..dddb6583a0b 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java @@ -55,9 +55,19 @@ public void testGetSubProperties() { source.put(KEY_PREFIX + "." + KEY_AGE, 31); Map expected = new HashMap(); - expected.put(KEY_NAME, "Mercy"); + expected.put(KEY_NAME, "mercyblitz"); expected.put(KEY_AGE, "31"); + + Map source2 = new HashMap(); + + source2.put("user.name", "mercyblitz"); + + MapPropertySource propertySource2 = new MapPropertySource("test2", source2); + + propertySources.addFirst(propertySource2); + + result = PropertySourcesUtils.getSubProperties(propertySources, KEY_PREFIX); Assert.assertEquals(expected, result); From 185545efe506542124cdf0144b160bdd8b1407bd Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Mon, 13 Aug 2018 10:08:04 +0800 Subject: [PATCH 09/38] Reactor ReferenceAnnotationBeanPostProcessor --- dependencies-bom/pom.xml | 18 +- dubbo-config/dubbo-config-spring/pom.xml | 4 + .../AbstractAnnotationConfigBeanBuilder.java | 3 +- .../ReferenceAnnotationBeanPostProcessor.java | 466 +++--------------- ...erenceAnnotationBeanPostProcessorTest.java | 11 +- 5 files changed, 108 insertions(+), 394 deletions(-) diff --git a/dependencies-bom/pom.xml b/dependencies-bom/pom.xml index e9a3f80b2c5..a6742b71d27 100644 --- a/dependencies-bom/pom.xml +++ b/dependencies-bom/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 @@ -29,8 +30,8 @@ https://github.com/apache/incubator-dubbo scm:git:https://github.com/apache/incubator-dubbo.git scm:git:https://github.com/apache/incubator-dubbo.git - HEAD - + HEAD + Development List @@ -101,6 +102,9 @@ 2.0 3.0.19.Final 8.5.31 + + + 1.0.1-SNAPSHOT 1.7.25 1.2 @@ -300,6 +304,14 @@ tomcat-embed-logging-juli ${tomcat_embed_version} + + + + com.alibaba.spring + spring-context-support + ${alibaba_spring_context_support_version} + + org.slf4j diff --git a/dubbo-config/dubbo-config-spring/pom.xml b/dubbo-config/dubbo-config-spring/pom.xml index a186182c49a..ff528b05195 100644 --- a/dubbo-config/dubbo-config-spring/pom.xml +++ b/dubbo-config/dubbo-config-spring/pom.xml @@ -56,6 +56,10 @@ javax.servlet-api provided + + com.alibaba.spring + spring-context-support + com.alibaba dubbo-registry-default 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 fc8d3f46105..2f58a6ec3b7 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 @@ -34,6 +34,7 @@ /** * Abstract Configurable {@link Annotation} Bean Builder + * * @since 2.5.7 */ abstract class AbstractAnnotationConfigBeanBuilder { @@ -76,7 +77,7 @@ public final B build() throws Exception { 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 cfd719668ae..8c8824f13f3 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,247 +18,55 @@ 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.spring.beans.factory.annotation.CustomizedAnnotationBeanPostProcessor; 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.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.util.Collection; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; +import java.lang.reflect.Proxy; +import java.util.*; 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 CustomizedAnnotationBeanPostProcessor + 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; - private ClassLoader classLoader; - - private final ConcurrentMap injectionMetadataCache = - new ConcurrentHashMap(256); - - private final ConcurrentMap> referenceBeansCache = - new ConcurrentHashMap>(); - - @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; - } - - - /** - * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link Reference @Reference} fields - * - * @param beanClass The {@link Class} of Bean - * @return non-null {@link List} - */ - private List findFieldReferenceMetadata(final Class beanClass) { - - final List elements = new LinkedList(); - - 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; - - } + private final List> referenceBeans = new LinkedList>(); - /** - * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link Reference @Reference} methods - * - * @param beanClass The {@link Class} of Bean - * @return non-null {@link List} - */ - private List findMethodReferenceMetadata(final Class beanClass) { - - final List elements = new LinkedList(); - - 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; + private final List referenceBeanInvocationHandlers = + new LinkedList(); - } + private final ConcurrentMap> injectedFieldReferenceBeanMap = + new ConcurrentHashMap>(); + private final ConcurrentMap> injectedMethodReferenceBeanMap = + new ConcurrentHashMap>(); - /** - * @param beanClass - * @return - */ - private ReferenceInjectionMetadata buildReferenceMetadata(final Class beanClass) { - Collection fieldElements = findFieldReferenceMetadata(beanClass); - Collection 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; - } - - @Override - public void destroy() throws Exception { - - for (ReferenceBean referenceBean : referenceBeansCache.values()) { - if (logger.isInfoEnabled()) { - logger.info(referenceBean + " was destroying!"); - } - referenceBean.destroy(); - } - - injectionMetadataCache.clear(); - referenceBeansCache.clear(); - - if (logger.isInfoEnabled()) { - logger.info(getClass() + " was destroying!"); - } - - } - - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } - - /** * Gets all beans of {@link ReferenceBean} * @@ -266,154 +74,7 @@ public void setBeanClassLoader(ClassLoader classLoader) { * @since 2.5.9 */ public Collection> getReferenceBeans() { - return this.referenceBeansCache.values(); - } - - - /** - * {@link Reference} {@link InjectionMetadata} implementation - * - * @since 2.5.11 - */ - private static class ReferenceInjectionMetadata extends InjectionMetadata { - - private final Collection fieldElements; - - private final Collection methodElements; - - - public ReferenceInjectionMetadata(Class targetClass, Collection fieldElements, - Collection methodElements) { - super(targetClass, combine(fieldElements, methodElements)); - this.fieldElements = fieldElements; - this.methodElements = methodElements; - } - - private static Collection combine(Collection... elements) { - List allElements = new ArrayList(); - for (Collection e : elements) { - allElements.addAll(e); - } - return allElements; - } - - public Collection getFieldElements() { - return fieldElements; - } - - public Collection getMethodElements() { - return methodElements; - } - } - - /** - * {@link Reference} {@link Method} {@link InjectionMetadata.InjectedElement} - */ - private class ReferenceMethodElement extends InjectionMetadata.InjectedElement { - - private final Method method; - - private final Reference reference; - - private volatile ReferenceBean referenceBean; - - protected ReferenceMethodElement(Method method, PropertyDescriptor pd, Reference reference) { - super(method, pd); - this.method = method; - this.reference = reference; - } - - @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()); - - } - - } - - /** - * {@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; - } - - @Override - protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { - - Class referenceClass = field.getType(); - - referenceBean = buildReferenceBean(reference, referenceClass); - - ReflectionUtils.makeAccessible(field); - - field.set(bean, referenceBean.getObject()); - - } - - } - - private ReferenceBean buildReferenceBean(Reference reference, Class referenceClass) throws Exception { - - String referenceBeanCacheKey = generateReferenceBeanCacheKey(reference, referenceClass); - - ReferenceBean referenceBean = referenceBeansCache.get(referenceBeanCacheKey); - - if (referenceBean == null) { - - ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder - .create(reference, classLoader, applicationContext) - .interfaceClass(referenceClass); - - referenceBean = beanBuilder.build(); - - referenceBeansCache.putIfAbsent(referenceBeanCacheKey, 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; - + return Collections.unmodifiableCollection(referenceBeans); } private static String resolveInterfaceName(Reference reference, Class beanClass) @@ -444,24 +105,7 @@ private static String resolveInterfaceName(Reference reference, Class beanCla * @since 2.5.11 */ public Map> getInjectedFieldReferenceBeanMap() { - - Map> injectedElementReferenceBeanMap = - new LinkedHashMap>(); - - for (ReferenceInjectionMetadata metadata : injectionMetadataCache.values()) { - - Collection fieldElements = metadata.getFieldElements(); - - for (ReferenceFieldElement fieldElement : fieldElements) { - - injectedElementReferenceBeanMap.put(fieldElement, fieldElement.referenceBean); - - } - - } - - return injectedElementReferenceBeanMap; - + return Collections.unmodifiableMap(injectedFieldReferenceBeanMap); } /** @@ -471,35 +115,87 @@ public Map> getInjectedField * @since 2.5.11 */ public Map> getInjectedMethodReferenceBeanMap() { + return Collections.unmodifiableMap(injectedMethodReferenceBeanMap); + } - Map> injectedElementReferenceBeanMap = - new LinkedHashMap>(); + @Override + protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class injectedType, + InjectionMetadata.InjectedElement injectedElement) throws Exception { + + ReferenceBean referenceBean = buildReferenceBean(reference, injectedType, getClassLoader(), injectedElement); - for (ReferenceInjectionMetadata metadata : injectionMetadataCache.values()) { + InvocationHandler handler = buildReferenceBeanInvocationHandler(referenceBean); - Collection methodElements = metadata.getMethodElements(); + Object proxy = Proxy.newProxyInstance(getClassLoader(), new Class[]{injectedType}, handler); - for (ReferenceMethodElement methodElement : methodElements) { + return proxy; + } + + private InvocationHandler buildReferenceBeanInvocationHandler(ReferenceBean referenceBean) { + ReferenceBeanInvocationHandler handler = new ReferenceBeanInvocationHandler(referenceBean); + referenceBeanInvocationHandlers.add(handler); + return handler; + } - injectedElementReferenceBeanMap.put(methodElement, methodElement.referenceBean); + private static class ReferenceBeanInvocationHandler implements InvocationHandler { - } + private final ReferenceBean referenceBean; + private ReferenceBeanInvocationHandler(ReferenceBean referenceBean) { + this.referenceBean = referenceBean; } - return injectedElementReferenceBeanMap; + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Object bean = referenceBean.get(); + return method.invoke(bean, args); + } + } + + @Override + protected String buildInjectedObjectCacheKey(Reference reference, Object bean, String beanName, Class injectedType) { + + String interfaceName = resolveInterfaceName(reference, injectedType); + + String key = reference.url() + "/" + interfaceName + + "/" + reference.version() + + "/" + reference.group(); + + key = getEnvironment().resolvePlaceholders(key); + return key; } - private T getFieldValue(Object object, String fieldName, Class fieldType) { + private ReferenceBean buildReferenceBean(Reference reference, Class referencedType, + ClassLoader classLoader, InjectionMetadata.InjectedElement injectedElement) throws Exception { + + ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder + .create(reference, classLoader, applicationContext) + .interfaceClass(referencedType); - Field field = ReflectionUtils.findField(object.getClass(), fieldName, fieldType); + ReferenceBean referenceBean = beanBuilder.build(); - ReflectionUtils.makeAccessible(field); + referenceBeans.add(referenceBean); - return (T) ReflectionUtils.getField(field, object); + if (injectedElement.getMember() instanceof Field) { + injectedFieldReferenceBeanMap.put(injectedElement, referenceBean); + } else if (injectedElement.getMember() instanceof Method) { + injectedMethodReferenceBeanMap.put(injectedElement, referenceBean); + } + + return referenceBean; } + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + + if (referenceBeanInvocationHandlers.isEmpty()) { + return; + } + + // clear all + referenceBeanInvocationHandlers.clear(); + } } 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 a1b5807cbf9..32adb9c8cdf 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 @@ -16,6 +16,7 @@ */ package com.alibaba.dubbo.config.spring.beans.factory.annotation; +import com.alibaba.dubbo.common.utils.NetUtils; import com.alibaba.dubbo.config.annotation.Reference; import com.alibaba.dubbo.config.spring.ReferenceBean; import com.alibaba.dubbo.config.spring.api.DemoService; @@ -56,7 +57,7 @@ public static void prepare() { 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"); + System.setProperty("consumer.url", "dubbo://" + NetUtils.getLocalHost() + ":12345"); } @Before @@ -136,13 +137,13 @@ public void testGetInjectedFieldReferenceBeanMap() { 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.CustomizedAnnotationBeanPostProcessor$AnnotatedFieldElement", injectedElement.getClass().getName()); ReferenceBean referenceBean = entry.getValue(); Assert.assertEquals("1.2", referenceBean.getVersion()); - Assert.assertEquals("dubbo://127.0.0.1:12345", referenceBean.getUrl()); + Assert.assertEquals("dubbo://" + NetUtils.getLocalHost() + ":12345", referenceBean.getUrl()); } @@ -166,7 +167,7 @@ public void testGetInjectedMethodReferenceBeanMap() { 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.CustomizedAnnotationBeanPostProcessor$AnnotatedMethodlement", injectedElement.getClass().getName()); ReferenceBean referenceBean = entry.getValue(); @@ -192,7 +193,7 @@ public void testModuleInfo() { for (Map.Entry> entry : referenceBeanMap.entrySet()) { ReferenceBean referenceBean = entry.getValue(); - assertThat(referenceBean.getModule().getName(),is("defaultModule")); + assertThat(referenceBean.getModule().getName(), is("defaultModule")); assertThat(referenceBean.getMonitor(), not(nullValue())); } } From 3f99fe126211e17d95e2eeb82bed58d786332930 Mon Sep 17 00:00:00 2001 From: "taogu.mxx" Date: Mon, 13 Aug 2018 15:18:50 +0800 Subject: [PATCH 10/38] Fixed incubator-dubbo-spring-boot-project#243 --- .../ReferenceAnnotationBeanPostProcessor.java | 151 +++++++++++++----- ...erenceAnnotationBeanPostProcessorTest.java | 30 ++-- 2 files changed, 117 insertions(+), 64 deletions(-) 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 8c8824f13f3..aa2c602f211 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 @@ -30,7 +30,9 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -48,33 +50,35 @@ public class ReferenceAnnotationBeanPostProcessor extends CustomizedAnnotationBe */ public static final String BEAN_NAME = "referenceAnnotationBeanPostProcessor"; - private ApplicationContext applicationContext; + /** + * Cache size + */ + private static final int CACHE_SIZE = Integer.getInteger(BEAN_NAME + ".cache.size", 32); - private final List> referenceBeans = new LinkedList>(); + private final ConcurrentMap> referenceBeanCache = + new ConcurrentHashMap>(CACHE_SIZE); - private final List referenceBeanInvocationHandlers = - new LinkedList(); + private final ConcurrentHashMap proxyCache = new ConcurrentHashMap(CACHE_SIZE); - private final ConcurrentMap> injectedFieldReferenceBeanMap = - new ConcurrentHashMap>(); + private final ConcurrentHashMap referenceBeanInvocationHandlerCache = + new ConcurrentHashMap(CACHE_SIZE); - private final ConcurrentMap> injectedMethodReferenceBeanMap = - new ConcurrentHashMap>(); + private final ConcurrentMap> injectedFieldReferenceBeanCache = + new ConcurrentHashMap>(CACHE_SIZE); + private final ConcurrentMap> injectedMethodReferenceBeanCache = + new ConcurrentHashMap>(CACHE_SIZE); - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } + private ApplicationContext applicationContext; /** * Gets all beans of {@link ReferenceBean} * - * @return non-null {@link Collection} + * @return non-null read-only {@link Collection} * @since 2.5.9 */ public Collection> getReferenceBeans() { - return Collections.unmodifiableCollection(referenceBeans); + return referenceBeanCache.values(); } private static String resolveInterfaceName(Reference reference, Class beanClass) @@ -105,7 +109,7 @@ private static String resolveInterfaceName(Reference reference, Class beanCla * @since 2.5.11 */ public Map> getInjectedFieldReferenceBeanMap() { - return Collections.unmodifiableMap(injectedFieldReferenceBeanMap); + return Collections.unmodifiableMap(injectedFieldReferenceBeanCache); } /** @@ -115,25 +119,46 @@ public Map> getInjectedField * @since 2.5.11 */ public Map> getInjectedMethodReferenceBeanMap() { - return Collections.unmodifiableMap(injectedMethodReferenceBeanMap); + return Collections.unmodifiableMap(injectedMethodReferenceBeanCache); } @Override protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class injectedType, InjectionMetadata.InjectedElement injectedElement) throws Exception { - ReferenceBean referenceBean = buildReferenceBean(reference, injectedType, getClassLoader(), injectedElement); + String referenceBeanCacheKey = buildReferenceBeanCacheKey(reference, injectedType); + + ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referenceBeanCacheKey, reference, injectedType, getClassLoader()); - InvocationHandler handler = buildReferenceBeanInvocationHandler(referenceBean); + cacheInjectedReferenceBean(referenceBean, injectedElement); - Object proxy = Proxy.newProxyInstance(getClassLoader(), new Class[]{injectedType}, handler); + Object proxy = buildProxyIfAbsent(referenceBeanCacheKey, referenceBean, injectedType); return proxy; } - private InvocationHandler buildReferenceBeanInvocationHandler(ReferenceBean referenceBean) { - ReferenceBeanInvocationHandler handler = new ReferenceBeanInvocationHandler(referenceBean); - referenceBeanInvocationHandlers.add(handler); + private Object buildProxyIfAbsent(String referenceBeanCacheKey, ReferenceBean referenceBean, Class injectedType) { + + Object proxy = proxyCache.get(referenceBeanCacheKey); + + if (proxy == null) { + InvocationHandler handler = buildInvocationHandlerIfAbsent(referenceBeanCacheKey, referenceBean); + proxy = Proxy.newProxyInstance(getClassLoader(), new Class[]{injectedType}, handler); + proxyCache.put(referenceBeanCacheKey, proxy); + } + + return proxy; + } + + private InvocationHandler buildInvocationHandlerIfAbsent(String referenceBeanCacheKey, ReferenceBean referenceBean) { + + ReferenceBeanInvocationHandler handler = referenceBeanInvocationHandlerCache.get(referenceBeanCacheKey); + + if (handler == null) { + handler = new ReferenceBeanInvocationHandler(referenceBean); + referenceBeanInvocationHandlerCache.put(referenceBeanCacheKey, handler); + } + return handler; } @@ -141,61 +166,99 @@ private static class ReferenceBeanInvocationHandler implements InvocationHandler private final ReferenceBean referenceBean; + private Object bean; + private ReferenceBeanInvocationHandler(ReferenceBean referenceBean) { this.referenceBean = referenceBean; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - Object bean = referenceBean.get(); return method.invoke(bean, args); } + + private void init() { + this.bean = referenceBean.get(); + } } @Override - protected String buildInjectedObjectCacheKey(Reference reference, Object bean, String beanName, Class injectedType) { + protected String buildInjectedObjectCacheKey(Reference reference, Object bean, String beanName, + Class injectedType, InjectionMetadata.InjectedElement injectedElement) { + + String key = buildReferenceBeanCacheKey(reference, injectedType) + + "?source=" + (injectedElement.getMember()); + + return key; + } + + private String buildReferenceBeanCacheKey(Reference reference, Class injectedType) { String interfaceName = resolveInterfaceName(reference, injectedType); - String key = reference.url() + "/" + interfaceName + + String key = reference.url() + + "/" + interfaceName + "/" + reference.version() + "/" + reference.group(); - key = getEnvironment().resolvePlaceholders(key); - - return key; + return getEnvironment().resolvePlaceholders(key); } - private ReferenceBean buildReferenceBean(Reference reference, Class referencedType, - ClassLoader classLoader, InjectionMetadata.InjectedElement injectedElement) throws Exception { + private ReferenceBean buildReferenceBeanIfAbsent(String referenceBeanCacheKey, Reference reference, + Class referencedType, ClassLoader classLoader) + throws Exception { - ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder - .create(reference, classLoader, applicationContext) - .interfaceClass(referencedType); + ReferenceBean referenceBean = referenceBeanCache.get(referenceBeanCacheKey); - ReferenceBean referenceBean = beanBuilder.build(); + if (referenceBean == null) { + ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder + .create(reference, classLoader, applicationContext) + .interfaceClass(referencedType); + referenceBean = beanBuilder.build(); + referenceBeanCache.put(referenceBeanCacheKey, referenceBean); + } - referenceBeans.add(referenceBean); + return referenceBean; + } + private void cacheInjectedReferenceBean(ReferenceBean referenceBean, + InjectionMetadata.InjectedElement injectedElement) { if (injectedElement.getMember() instanceof Field) { - injectedFieldReferenceBeanMap.put(injectedElement, referenceBean); + injectedFieldReferenceBeanCache.put(injectedElement, referenceBean); } else if (injectedElement.getMember() instanceof Method) { - injectedMethodReferenceBeanMap.put(injectedElement, referenceBean); + injectedMethodReferenceBeanCache.put(injectedElement, referenceBean); } - - return referenceBean; - } + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } @Override public void onApplicationEvent(ContextRefreshedEvent event) { - if (referenceBeanInvocationHandlers.isEmpty()) { + if (proxyCache.isEmpty() || referenceBeanCache.isEmpty() || referenceBeanInvocationHandlerCache.isEmpty()) { return; } - // clear all - referenceBeanInvocationHandlers.clear(); + // initialize all + for (ReferenceBeanInvocationHandler handler : referenceBeanInvocationHandlerCache.values()) { + handler.init(); + } + + // clear Proxies and Handlers + this.proxyCache.clear(); + this.referenceBeanInvocationHandlerCache.clear(); + } + + @Override + public void destroy() throws Exception { + super.destroy(); + this.proxyCache.clear(); + this.referenceBeanCache.clear(); + this.referenceBeanInvocationHandlerCache.clear(); + this.injectedFieldReferenceBeanCache.clear(); + this.injectedMethodReferenceBeanCache.clear(); } } 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 32adb9c8cdf..005f1e33981 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 @@ -16,16 +16,11 @@ */ package com.alibaba.dubbo.config.spring.beans.factory.annotation; -import com.alibaba.dubbo.common.utils.NetUtils; 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.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.InjectionMetadata; import org.springframework.context.ApplicationContext; @@ -37,9 +32,7 @@ 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; /** @@ -57,7 +50,7 @@ public static void prepare() { 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://" + NetUtils.getLocalHost() + ":12345"); + System.setProperty("consumer.url", "dubbo://127.0.0.1:12345"); } @Before @@ -79,15 +72,14 @@ public void test() throws Exception { TestBean testBean = context.getBean(TestBean.class); + DemoService demoService = testBean.getDemoService(); + + Assert.assertEquals("annotation: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(); @@ -113,9 +105,7 @@ public void testGetReferenceBeans() { 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()); } @@ -143,7 +133,7 @@ public void testGetInjectedFieldReferenceBeanMap() { ReferenceBean referenceBean = entry.getValue(); Assert.assertEquals("1.2", referenceBean.getVersion()); - Assert.assertEquals("dubbo://" + NetUtils.getLocalHost() + ":12345", referenceBean.getUrl()); + Assert.assertEquals("dubbo://127.0.0.1:12345", referenceBean.getUrl()); } @@ -167,7 +157,7 @@ public void testGetInjectedMethodReferenceBeanMap() { InjectionMetadata.InjectedElement injectedElement = entry.getKey(); - Assert.assertEquals("com.alibaba.spring.beans.factory.annotation.CustomizedAnnotationBeanPostProcessor$AnnotatedMethodlement", + Assert.assertEquals("com.alibaba.spring.beans.factory.annotation.CustomizedAnnotationBeanPostProcessor$AnnotatedMethodElement", injectedElement.getClass().getName()); ReferenceBean referenceBean = entry.getValue(); From b066ccfe4ac5448cbe430b7992c354cfd13fc9fe Mon Sep 17 00:00:00 2001 From: "taogu.mxx" Date: Mon, 13 Aug 2018 17:17:37 +0800 Subject: [PATCH 11/38] Add ServiceBeanNameBuilder --- .../annotation/ServiceBeanNameBuilder.java | 139 ++++++++++++++++++ .../ServiceBeanNameBuilderTest.java | 92 ++++++++++++ 2 files changed, 231 insertions(+) create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java create mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java 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 00000000000..0020a57794d --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java @@ -0,0 +1,139 @@ +/* + * 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.ModuleConfig; +import com.alibaba.dubbo.config.RegistryConfig; +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.util.StringUtils; + +/** + * Dubbo {@link Service @Service} Bean Builder + * + * @author Mercy + * @see Service + * @see Reference + * @see ServiceBean + * @see ReferenceBean + * @since 2.6.4 + */ +class ServiceBeanNameBuilder { + + private static final String SEPARATOR = ":"; + + private final Class interfaceClass; + + private final String version; + + private final String group; + + private String application; + + private String module; + + + private String[] registry; + + private ServiceBeanNameBuilder(Class interfaceClass, String version, String group) { + this.interfaceClass = interfaceClass; + this.version = version; + this.group = group; + } + + private ServiceBeanNameBuilder(Service service, Class interfaceClass) { + this(service.interfaceClass() == null ? interfaceClass : service.interfaceClass(), service.version(), service.group()); + application(service.application()); + module(service.module()); + registry(service.registry()); + } + + private ServiceBeanNameBuilder(Reference reference, Class interfaceClass) { + this(reference.interfaceClass() == null ? interfaceClass : reference.interfaceClass(), reference.version(), reference.group()); + application(reference.application()); + module(reference.module()); + registry(reference.registry()); + } + + public static ServiceBeanNameBuilder create(Class interfaceClass, String version, String group) { + return new ServiceBeanNameBuilder(interfaceClass, version, group); + } + + public static ServiceBeanNameBuilder create(Service service, Class interfaceClass) { + return new ServiceBeanNameBuilder(service, interfaceClass); + } + + public static ServiceBeanNameBuilder create(Reference reference, Class interfaceClass) { + return new ServiceBeanNameBuilder(reference, interfaceClass); + } + + private static void append(StringBuilder builder, String value) { + if (StringUtils.hasText(value)) { + builder.append(value).append(SEPARATOR); + } + } + + /** + * Set {@link ApplicationConfig application} bean name + * + * @param application {@link ApplicationConfig application} bean name + * @return {@link ServiceBeanNameBuilder} + */ + public ServiceBeanNameBuilder application(String application) { + this.application = application; + return this; + } + + /** + * Set {@link ModuleConfig module} bean name + * + * @param module {@link ModuleConfig module} bean name + * @return {@link ServiceBeanNameBuilder} + */ + public ServiceBeanNameBuilder module(String module) { + this.module = module; + return this; + } + + /** + * Set {@link RegistryConfig monitor} bean names + * + * @param registry {@link RegistryConfig monitor} bean name + * @return {@link ServiceBeanNameBuilder} + */ + public ServiceBeanNameBuilder registry(String... registry) { + this.registry = registry; + return this; + } + + public String build() { + StringBuilder beanNameBuilder = new StringBuilder(); + // Required + append(beanNameBuilder, interfaceClass.getName()); + append(beanNameBuilder, version); + append(beanNameBuilder, group); + // Optional + append(beanNameBuilder, application); + append(beanNameBuilder, module); + append(beanNameBuilder, StringUtils.arrayToCommaDelimitedString(registry)); + // Build and remove last ":" + return beanNameBuilder.substring(0, beanNameBuilder.length() - 1); + } +} 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 00000000000..dcf1348ed9f --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java @@ -0,0 +1,92 @@ +/* + * 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.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 + * + * @author Mercy + * @see ServiceBeanNameBuilder + * @since 2.6.4 + */ +@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"; + + @Test + public void testRequiredAttributes() { + + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(INTERFACE_CLASS, VERSION, GROUP); + + Assert.assertEquals("com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO", builder.build()); + + } + + @Test + public void testServiceAnnotation() { + Service service = AnnotationUtils.getAnnotation(ServiceBeanNameBuilderTest.class, Service.class); + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, INTERFACE_CLASS); + Assert.assertEquals("com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO:application:module:1,2,3", + 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); + Assert.assertEquals("com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO:application:module:1,2,3", + builder.build()); + } + + @Test + public void testBuildAll() { + + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(INTERFACE_CLASS, VERSION, GROUP); + + builder.application("application"); + Assert.assertEquals("com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO:application", + builder.build()); + + builder.module("module"); + Assert.assertEquals("com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO:application:module", + builder.build()); + + builder.registry("1", "2", "3"); + Assert.assertEquals("com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO:application:module:1,2,3", + builder.build()); + + } +} From 80b6277438127c0aca9fe36a1e5063a25d87f9bf Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Mon, 13 Aug 2018 17:19:38 +0800 Subject: [PATCH 12/38] Polish apache/incubator-dubbo/#2235 --- .../spring/beans/factory/annotation/ServiceBeanNameBuilder.java | 1 - 1 file changed, 1 deletion(-) 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 index 0020a57794d..e6e0373bcb1 100644 --- 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 @@ -49,7 +49,6 @@ class ServiceBeanNameBuilder { private String module; - private String[] registry; private ServiceBeanNameBuilder(Class interfaceClass, String version, String group) { From cac7021bdb0fbd85cbbcec5f6a9a2513361b7071 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Tue, 14 Aug 2018 09:50:49 +0800 Subject: [PATCH 13/38] Polish incubator-dubbo#2251 --- .../dubbo/config/spring/ServiceBean.java | 56 ++++++-- .../ReferenceAnnotationBeanPostProcessor.java | 120 ++++++++---------- .../ServiceAnnotationBeanPostProcessor.java | 55 ++------ .../annotation/ServiceBeanNameBuilder.java | 102 ++++++--------- .../context/event/ServiceBeanExportEvent.java | 51 ++++++++ .../config/spring/util/AnnotationUtils.java | 42 ++++++ ...erenceAnnotationBeanPostProcessorTest.java | 113 ++++++++--------- ...erviceAnnotationBeanPostProcessorTest.java | 45 ++----- .../ServiceAnnotationTestConfiguration.java | 115 +++++++++++++++++ .../ServiceBeanNameBuilderTest.java | 38 ++---- .../context/annotation/EnableDubboTest.java | 38 +++--- .../annotation/provider/DemoServiceImpl.java | 2 +- 12 files changed, 450 insertions(+), 327 deletions(-) create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/event/ServiceBeanExportEvent.java create mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationTestConfiguration.java 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 b38684b2c75..56665faed09 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.ServiceBeanExportEvent; 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 @@ * * @export */ -public class ServiceBean extends ServiceConfig implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware { +public class ServiceBean extends ServiceConfig implements InitializingBean, DisposableBean, + ApplicationContextAware, ApplicationListener, BeanNameAware, + ApplicationEventPublisherAware { private static final long serialVersionUID = 213195494150089726L; @@ -60,6 +55,8 @@ public class ServiceBean extends ServiceConfig implements InitializingBean private transient boolean supportedApplicationListener; + private ApplicationEventPublisher applicationEventPublisher; + public ServiceBean() { super(); this.service = null; @@ -265,6 +262,34 @@ && getInterface() != null && getInterface().length() > 0 } } + /** + * Get the name of {@link ServiceBean} + * + * @return {@link ServiceBean}'s name + * @since 2.6.4 + */ + public String getBeanName() { + return this.beanName; + } + + /** + * @since 2.6.4 + */ + @Override + public void export() { + super.export(); + // Publish ServiceBeanExportEvent + publishExportEvent(); + } + + /** + * @since 2.6.4 + */ + private void publishExportEvent() { + ServiceBeanExportEvent exportEvent = new ServiceBeanExportEvent(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 @@ protected Class getServiceClass(T ref) { } return super.getServiceClass(ref); } + + /** + * @param applicationEventPublisher + * @since 2.6.4 + */ + @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/ReferenceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java index aa2c602f211..18b70554637 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,11 +18,14 @@ import com.alibaba.dubbo.config.annotation.Reference; import com.alibaba.dubbo.config.spring.ReferenceBean; -import com.alibaba.spring.beans.factory.annotation.CustomizedAnnotationBeanPostProcessor; +import com.alibaba.dubbo.config.spring.ServiceBean; +import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportEvent; +import com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.InjectionMetadata; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; @@ -42,8 +45,8 @@ * * @since 2.5.7 */ -public class ReferenceAnnotationBeanPostProcessor extends CustomizedAnnotationBeanPostProcessor - implements ApplicationContextAware, ApplicationListener { +public class ReferenceAnnotationBeanPostProcessor extends AnnotationInjectedBeanPostProcessor + implements ApplicationContextAware, ApplicationListener { /** * The bean name of {@link ReferenceAnnotationBeanPostProcessor} @@ -58,9 +61,7 @@ public class ReferenceAnnotationBeanPostProcessor extends CustomizedAnnotationBe private final ConcurrentMap> referenceBeanCache = new ConcurrentHashMap>(CACHE_SIZE); - private final ConcurrentHashMap proxyCache = new ConcurrentHashMap(CACHE_SIZE); - - private final ConcurrentHashMap referenceBeanInvocationHandlerCache = + private final ConcurrentHashMap localReferenceBeanInvocationHandlerCache = new ConcurrentHashMap(CACHE_SIZE); private final ConcurrentMap> injectedFieldReferenceBeanCache = @@ -81,27 +82,6 @@ public Collection> getReferenceBeans() { return referenceBeanCache.values(); } - 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."); - } - - return interfaceName; - - } - - /** * Get {@link ReferenceBean} {@link Map} in injected field. * @@ -126,37 +106,37 @@ public Map> getInjectedMetho protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class injectedType, InjectionMetadata.InjectedElement injectedElement) throws Exception { - String referenceBeanCacheKey = buildReferenceBeanCacheKey(reference, injectedType); + String referencedBeanName = buildReferencedBeanName(reference, injectedType); - ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referenceBeanCacheKey, reference, injectedType, getClassLoader()); + ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referencedBeanName, reference, injectedType, getClassLoader()); cacheInjectedReferenceBean(referenceBean, injectedElement); - Object proxy = buildProxyIfAbsent(referenceBeanCacheKey, referenceBean, injectedType); + Object proxy = buildProxy(referencedBeanName, referenceBean, injectedType); return proxy; } - private Object buildProxyIfAbsent(String referenceBeanCacheKey, ReferenceBean referenceBean, Class injectedType) { - - Object proxy = proxyCache.get(referenceBeanCacheKey); - - if (proxy == null) { - InvocationHandler handler = buildInvocationHandlerIfAbsent(referenceBeanCacheKey, referenceBean); - proxy = Proxy.newProxyInstance(getClassLoader(), new Class[]{injectedType}, handler); - proxyCache.put(referenceBeanCacheKey, proxy); - } - + 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 buildInvocationHandlerIfAbsent(String referenceBeanCacheKey, ReferenceBean referenceBean) { + private InvocationHandler buildInvocationHandler(String referencedBeanName, ReferenceBean referenceBean) { - ReferenceBeanInvocationHandler handler = referenceBeanInvocationHandlerCache.get(referenceBeanCacheKey); + ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.get(referencedBeanName); if (handler == null) { handler = new ReferenceBeanInvocationHandler(referenceBean); - referenceBeanInvocationHandlerCache.put(referenceBeanCacheKey, handler); + } + + 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(); } return handler; @@ -186,36 +166,31 @@ private void init() { protected String buildInjectedObjectCacheKey(Reference reference, Object bean, String beanName, Class injectedType, InjectionMetadata.InjectedElement injectedElement) { - String key = buildReferenceBeanCacheKey(reference, injectedType) + - "?source=" + (injectedElement.getMember()); + String key = buildReferencedBeanName(reference, injectedType) + + "#source=" + (injectedElement.getMember()); return key; } - private String buildReferenceBeanCacheKey(Reference reference, Class injectedType) { - - String interfaceName = resolveInterfaceName(reference, injectedType); + private String buildReferencedBeanName(Reference reference, Class injectedType) { - String key = reference.url() + - "/" + interfaceName + - "/" + reference.version() + - "/" + reference.group(); + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, injectedType, getEnvironment()); - return getEnvironment().resolvePlaceholders(key); + return getEnvironment().resolvePlaceholders(builder.build()); } - private ReferenceBean buildReferenceBeanIfAbsent(String referenceBeanCacheKey, Reference reference, + private ReferenceBean buildReferenceBeanIfAbsent(String referencedBeanName, Reference reference, Class referencedType, ClassLoader classLoader) throws Exception { - ReferenceBean referenceBean = referenceBeanCache.get(referenceBeanCacheKey); + ReferenceBean referenceBean = referenceBeanCache.get(referencedBeanName); if (referenceBean == null) { ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder .create(reference, classLoader, applicationContext) .interfaceClass(referencedType); referenceBean = beanBuilder.build(); - referenceBeanCache.put(referenceBeanCacheKey, referenceBean); + referenceBeanCache.put(referencedBeanName, referenceBean); } return referenceBean; @@ -236,28 +211,39 @@ public void setApplicationContext(ApplicationContext applicationContext) throws } @Override - public void onApplicationEvent(ContextRefreshedEvent event) { - - if (proxyCache.isEmpty() || referenceBeanCache.isEmpty() || referenceBeanInvocationHandlerCache.isEmpty()) { - return; + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof ServiceBeanExportEvent) { + onServiceBeanExportEvent((ServiceBeanExportEvent) event); + } else if (event instanceof ContextRefreshedEvent) { + onContextRefreshedEvent((ContextRefreshedEvent) event); } + } + + private void onServiceBeanExportEvent(ServiceBeanExportEvent event) { + ServiceBean serviceBean = event.getServiceBean(); + initReferenceBeanInvocationHandler(serviceBean); + } - // initialize all - for (ReferenceBeanInvocationHandler handler : referenceBeanInvocationHandlerCache.values()) { + 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(); } + } + + private void onContextRefreshedEvent(ContextRefreshedEvent event) { - // clear Proxies and Handlers - this.proxyCache.clear(); - this.referenceBeanInvocationHandlerCache.clear(); } + @Override public void destroy() throws Exception { super.destroy(); - this.proxyCache.clear(); this.referenceBeanCache.clear(); - this.referenceBeanInvocationHandlerCache.clear(); + this.localReferenceBeanInvocationHandlerCache.clear(); this.injectedFieldReferenceBeanCache.clear(); this.injectedMethodReferenceBeanCache.clear(); } 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 35604650906..f92173d6c1a 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 @@ -24,17 +24,8 @@ import org.springframework.beans.BeansException; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.beans.factory.config.SingletonBeanRegistry; -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; -import org.springframework.beans.factory.support.BeanNameGenerator; -import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.config.*; +import org.springframework.beans.factory.support.*; import org.springframework.context.EnvironmentAware; import org.springframework.context.ResourceLoaderAware; import org.springframework.context.annotation.AnnotationBeanNameGenerator; @@ -44,17 +35,9 @@ import org.springframework.core.env.Environment; import org.springframework.core.io.ResourceLoader; import org.springframework.core.type.filter.AnnotationTypeFilter; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.util.CollectionUtils; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; - -import java.util.Arrays; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; +import org.springframework.util.*; + +import java.util.*; import static com.alibaba.dubbo.config.spring.util.ObjectUtils.of; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; @@ -71,8 +54,6 @@ public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, ResourceLoaderAware, BeanClassLoaderAware { - private static final String SEPARATOR = ":"; - private final Logger logger = LoggerFactory.getLogger(getClass()); private final Set packagesToScan; @@ -262,7 +243,7 @@ private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, Bean registry.registerBeanDefinition(beanName, serviceBeanDefinition); if (logger.isInfoEnabled()) { - logger.warn("The BeanDefinition[" + serviceBeanDefinition + + logger.info("The BeanDefinition[" + serviceBeanDefinition + "] of ServiceBean has been registered with name : " + beanName); } @@ -271,7 +252,7 @@ private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, Bean if (logger.isWarnEnabled()) { logger.warn("The Duplicated BeanDefinition[" + serviceBeanDefinition + "] of ServiceBean[ bean name : " + beanName + - "] was be found , Did @DubboComponentScan scan to same package in many times?"); + "] was be found!"); } } @@ -289,27 +270,9 @@ private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, Bean */ private String generateServiceBeanName(Service service, Class interfaceClass, String annotatedServiceBeanName) { - StringBuilder beanNameBuilder = new StringBuilder(ServiceBean.class.getSimpleName()); - - 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); - } + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, interfaceClass, environment); - 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 index e6e0373bcb1..14556eab140 100644 --- 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 @@ -16,15 +16,15 @@ */ package com.alibaba.dubbo.config.spring.beans.factory.annotation; -import com.alibaba.dubbo.config.ApplicationConfig; -import com.alibaba.dubbo.config.ModuleConfig; -import com.alibaba.dubbo.config.RegistryConfig; 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 * @@ -39,48 +39,46 @@ class ServiceBeanNameBuilder { private static final String SEPARATOR = ":"; - private final Class interfaceClass; - - private final String version; + private final String interfaceClassName; - private final String group; + private final Environment environment; - private String application; + // Optional + private String version; - private String module; + private String group; - private String[] registry; + private ServiceBeanNameBuilder(String interfaceClassName, Environment environment) { + this.interfaceClassName = interfaceClassName; + this.environment = environment; + } - private ServiceBeanNameBuilder(Class interfaceClass, String version, String group) { - this.interfaceClass = interfaceClass; - this.version = version; - this.group = group; + private ServiceBeanNameBuilder(Class interfaceClass, Environment environment) { + this(interfaceClass.getName(), environment); } - private ServiceBeanNameBuilder(Service service, Class interfaceClass) { - this(service.interfaceClass() == null ? interfaceClass : service.interfaceClass(), service.version(), service.group()); - application(service.application()); - module(service.module()); - registry(service.registry()); + 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) { - this(reference.interfaceClass() == null ? interfaceClass : reference.interfaceClass(), reference.version(), reference.group()); - application(reference.application()); - module(reference.module()); - registry(reference.registry()); + 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, String version, String group) { - return new ServiceBeanNameBuilder(interfaceClass, version, group); + public static ServiceBeanNameBuilder create(Class interfaceClass, Environment environment) { + return new ServiceBeanNameBuilder(interfaceClass, environment); } - public static ServiceBeanNameBuilder create(Service service, Class interfaceClass) { - return new ServiceBeanNameBuilder(service, interfaceClass); + public static ServiceBeanNameBuilder create(Service service, Class interfaceClass, Environment environment) { + return new ServiceBeanNameBuilder(service, interfaceClass, environment); } - public static ServiceBeanNameBuilder create(Reference reference, Class interfaceClass) { - return new ServiceBeanNameBuilder(reference, interfaceClass); + public static ServiceBeanNameBuilder create(Reference reference, Class interfaceClass, Environment environment) { + return new ServiceBeanNameBuilder(reference, interfaceClass, environment); } private static void append(StringBuilder builder, String value) { @@ -89,50 +87,26 @@ private static void append(StringBuilder builder, String value) { } } - /** - * Set {@link ApplicationConfig application} bean name - * - * @param application {@link ApplicationConfig application} bean name - * @return {@link ServiceBeanNameBuilder} - */ - public ServiceBeanNameBuilder application(String application) { - this.application = application; - return this; - } - - /** - * Set {@link ModuleConfig module} bean name - * - * @param module {@link ModuleConfig module} bean name - * @return {@link ServiceBeanNameBuilder} - */ - public ServiceBeanNameBuilder module(String module) { - this.module = module; + public ServiceBeanNameBuilder group(String group) { + this.group = group; return this; } - /** - * Set {@link RegistryConfig monitor} bean names - * - * @param registry {@link RegistryConfig monitor} bean name - * @return {@link ServiceBeanNameBuilder} - */ - public ServiceBeanNameBuilder registry(String... registry) { - this.registry = registry; + public ServiceBeanNameBuilder version(String version) { + this.version = version; return this; } public String build() { - StringBuilder beanNameBuilder = new StringBuilder(); + StringBuilder beanNameBuilder = new StringBuilder("ServiceBean").append(SEPARATOR); // Required - append(beanNameBuilder, interfaceClass.getName()); + append(beanNameBuilder, interfaceClassName); + // Optional append(beanNameBuilder, version); append(beanNameBuilder, group); - // Optional - append(beanNameBuilder, application); - append(beanNameBuilder, module); - append(beanNameBuilder, StringUtils.arrayToCommaDelimitedString(registry)); // Build and remove last ":" - return beanNameBuilder.substring(0, beanNameBuilder.length() - 1); + String rawBeanName = beanNameBuilder.substring(0, beanNameBuilder.length() - 1); + // Resolve placeholders + return environment.resolvePlaceholders(rawBeanName); } } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/event/ServiceBeanExportEvent.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/event/ServiceBeanExportEvent.java new file mode 100644 index 00000000000..ac352e6fb38 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/event/ServiceBeanExportEvent.java @@ -0,0 +1,51 @@ +/* + * 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 + * + * @author Mercy + * @see ApplicationEvent + * @see ApplicationListener + * @see ServiceBean + * @since 2.6.4 + */ +public class ServiceBeanExportEvent extends ApplicationEvent { + + /** + * Create a new ApplicationEvent. + * + * @param serviceBean {@link ServiceBean} bean + */ + public ServiceBeanExportEvent(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/util/AnnotationUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotationUtils.java index aa15e567eb0..87f82d3063d 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 static Map getAttributes(Annotation annotation, PropertyR } + 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; + + } + } 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 005f1e33981..eba43b2a599 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,14 +19,17 @@ 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.*; +import org.junit.Assert; +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; @@ -40,49 +43,48 @@ * * @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("annotation:Mercy", demoService.sayName("Mercy")); + Assert.assertEquals("Hello,Mercy", demoService.sayName("Mercy")); Assert.assertNotNull(testBean.getDemoServiceFromAncestor()); Assert.assertNotNull(testBean.getDemoServiceFromParent()); Assert.assertNotNull(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")); } @@ -92,8 +94,6 @@ public void test() throws Exception { @Test public void testGetReferenceBeans() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); - ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class); @@ -112,8 +112,6 @@ public void testGetReferenceBeans() { @Test public void testGetInjectedFieldReferenceBeanMap() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); - ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class); @@ -127,12 +125,12 @@ public void testGetInjectedFieldReferenceBeanMap() { InjectionMetadata.InjectedElement injectedElement = entry.getKey(); - Assert.assertEquals("com.alibaba.spring.beans.factory.annotation.CustomizedAnnotationBeanPostProcessor$AnnotatedFieldElement", + 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()); } @@ -142,8 +140,6 @@ public void testGetInjectedFieldReferenceBeanMap() { @Test public void testGetInjectedMethodReferenceBeanMap() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); - ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class); @@ -157,36 +153,35 @@ public void testGetInjectedMethodReferenceBeanMap() { InjectionMetadata.InjectedElement injectedElement = entry.getKey(); - Assert.assertEquals("com.alibaba.spring.beans.factory.annotation.CustomizedAnnotationBeanPostProcessor$AnnotatedMethodElement", + 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> referenceBeanMap = - beanPostProcessor.getInjectedMethodReferenceBeanMap(); - - for (Map.Entry> 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> referenceBeanMap = +// beanPostProcessor.getInjectedMethodReferenceBeanMap(); +// +// for (Map.Entry> entry : referenceBeanMap.entrySet()) { +// ReferenceBean referenceBean = entry.getValue(); +// +// assertThat(referenceBean.getModule().getName(), is("defaultModule")); +// assertThat(referenceBean.getMonitor(), not(nullValue())); +// } +// } private static class AncestorBean { @@ -200,7 +195,7 @@ public DemoService getDemoServiceFromAncestor() { 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; } @@ -224,8 +219,6 @@ public DemoService getDemoServiceFromParent() { } - @ImportResource("META-INF/spring/dubbo-annotation-consumer.xml") - @DubboComponentScan(basePackageClasses = ReferenceAnnotationBeanPostProcessorTest.class) static class TestBean extends ParentBean { private DemoService demoService; @@ -237,7 +230,7 @@ public DemoService getDemoService() { 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 c0964418144..6133c48aaba 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.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 @@ */ @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 void test() { Map serviceBeansMap = beanFactory.getBeansOfType(ServiceBean.class); - Assert.assertEquals(3, serviceBeansMap.size()); + Assert.assertEquals(2, serviceBeansMap.size()); Map 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 00000000000..c2f59239041 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationTestConfiguration.java @@ -0,0 +1,115 @@ +/* + * 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 + * + * @author Mercy + * @since 2.6.4 + */ +@PropertySource("META-INF/default.properties") +public class ServiceAnnotationTestConfiguration { + + /** + * Current application configuration, to replace XML config: + * + * <dubbo:application name="dubbo-annotation-provider"/> + * + * + * @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: + * + * <dubbo:registry id="my-registry" address="N/A"/> + * + * + * @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: + * + * <dubbo:protocol name="dubbo" port="12345"/> + * + * + * @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 index dcf1348ed9f..83363691e45 100644 --- 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 @@ -22,6 +22,7 @@ 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; @@ -46,47 +47,30 @@ public class ServiceBeanNameBuilderTest { static final String VERSION = "1.0.0"; - @Test - public void testRequiredAttributes() { + static final String BEAN_NAME = "ServiceBean:com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO"; - ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(INTERFACE_CLASS, VERSION, GROUP); - - Assert.assertEquals("com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO", builder.build()); + 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); - Assert.assertEquals("com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO:application:module:1,2,3", + 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); - Assert.assertEquals("com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO:application:module:1,2,3", + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, INTERFACE_CLASS, environment); + Assert.assertEquals(BEAN_NAME, builder.build()); } - @Test - public void testBuildAll() { - - ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(INTERFACE_CLASS, VERSION, GROUP); - - builder.application("application"); - Assert.assertEquals("com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO:application", - builder.build()); - - builder.module("module"); - Assert.assertEquals("com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO:application:module", - builder.build()); - - builder.registry("1", "2", "3"); - Assert.assertEquals("com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO:application:module:1,2,3", - builder.build()); - - } } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboTest.java index c5018da2522..4f71ce148fd 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboTest.java @@ -23,12 +23,14 @@ import com.alibaba.dubbo.config.spring.context.annotation.provider.DemoServiceImpl; import org.junit.Assert; import org.junit.Test; +import org.junit.runner.RunWith; import org.springframework.aop.support.AopUtils; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Primary; -import org.springframework.context.annotation.PropertySource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.*; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; @@ -43,17 +45,21 @@ * * @since 2.5.8 */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = {EnableDubboTest.class}) +@TestPropertySource(locations = "classpath:/META-INF/dubbb-provider.properties", + properties = "demo.service.version = 2.5.7") +@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.config.spring.context.annotation.provider") +@ComponentScan(basePackages = "com.alibaba.dubbo.config.spring.context.annotation.provider") +@EnableTransactionManagement public class EnableDubboTest { + @Autowired + private ApplicationContext providerContext; + @Test public void test() { - AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext(); - - providerContext.register(TestProviderConfiguration.class); - - providerContext.refresh(); - DemoService demoService = providerContext.getBean(DemoService.class); String value = demoService.sayName("Mercy"); @@ -68,11 +74,7 @@ public void test() { // Test @Transactional is present or not Assert.assertNotNull(findAnnotation(beanClass, Transactional.class)); - AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(); - - consumerContext.register(TestConsumerConfiguration.class); - - consumerContext.refresh(); + AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(TestConsumerConfiguration.class); TestConsumerConfiguration consumerConfiguration = consumerContext.getBean(TestConsumerConfiguration.class); @@ -127,10 +129,6 @@ public void test() { // Test multiple binding Assert.assertEquals("N/A", registryConfig.getAddress()); - providerContext.close(); - consumerContext.close(); - - } @EnableDubbo(scanBasePackages = "com.alibaba.dubbo.config.spring.context.annotation.provider") diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java index 9961aa27a85..96a6b1af737 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java @@ -28,7 +28,7 @@ * @since 2.5.8 */ @com.alibaba.dubbo.config.annotation.Service( - version = "2.5.7", + version = "${demo.service.version}", application = "${demo.service.application}", protocol = "${demo.service.protocol}", registry = "${demo.service.registry}" From a8f4f732ac1fdad3e99effa798568bdd3db35287 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Tue, 14 Aug 2018 10:12:23 +0800 Subject: [PATCH 14/38] Update spring-context-supprt version to be release --- dependencies-bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies-bom/pom.xml b/dependencies-bom/pom.xml index a6742b71d27..6f06c22a7a5 100644 --- a/dependencies-bom/pom.xml +++ b/dependencies-bom/pom.xml @@ -104,7 +104,7 @@ 8.5.31 - 1.0.1-SNAPSHOT + 1.0.1 1.7.25 1.2 From 593ce643221e2b02d56dcd9b43aa0d62ed7e6fcf Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Tue, 14 Aug 2018 10:25:04 +0800 Subject: [PATCH 15/38] Rename ServiceBeanExportEvent to be ServiceBeanExportedEvent --- .../java/com/alibaba/dubbo/config/spring/ServiceBean.java | 6 +++--- .../annotation/ReferenceAnnotationBeanPostProcessor.java | 8 ++++---- ...BeanExportEvent.java => ServiceBeanExportedEvent.java} | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) rename dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/event/{ServiceBeanExportEvent.java => ServiceBeanExportedEvent.java} (92%) 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 56665faed09..d03f4c1a31b 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 @@ -18,7 +18,7 @@ import com.alibaba.dubbo.config.*; import com.alibaba.dubbo.config.annotation.Service; -import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportEvent; +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; @@ -278,7 +278,7 @@ public String getBeanName() { @Override public void export() { super.export(); - // Publish ServiceBeanExportEvent + // Publish ServiceBeanExportedEvent publishExportEvent(); } @@ -286,7 +286,7 @@ public void export() { * @since 2.6.4 */ private void publishExportEvent() { - ServiceBeanExportEvent exportEvent = new ServiceBeanExportEvent(this); + ServiceBeanExportedEvent exportEvent = new ServiceBeanExportedEvent(this); applicationEventPublisher.publishEvent(exportEvent); } 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 18b70554637..37debea5e19 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 @@ -19,7 +19,7 @@ import com.alibaba.dubbo.config.annotation.Reference; import com.alibaba.dubbo.config.spring.ReferenceBean; import com.alibaba.dubbo.config.spring.ServiceBean; -import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportEvent; +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.factory.annotation.InjectionMetadata; @@ -212,14 +212,14 @@ public void setApplicationContext(ApplicationContext applicationContext) throws @Override public void onApplicationEvent(ApplicationEvent event) { - if (event instanceof ServiceBeanExportEvent) { - onServiceBeanExportEvent((ServiceBeanExportEvent) event); + if (event instanceof ServiceBeanExportedEvent) { + onServiceBeanExportEvent((ServiceBeanExportedEvent) event); } else if (event instanceof ContextRefreshedEvent) { onContextRefreshedEvent((ContextRefreshedEvent) event); } } - private void onServiceBeanExportEvent(ServiceBeanExportEvent event) { + private void onServiceBeanExportEvent(ServiceBeanExportedEvent event) { ServiceBean serviceBean = event.getServiceBean(); initReferenceBeanInvocationHandler(serviceBean); } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/event/ServiceBeanExportEvent.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/event/ServiceBeanExportedEvent.java similarity index 92% rename from dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/event/ServiceBeanExportEvent.java rename to dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/event/ServiceBeanExportedEvent.java index ac352e6fb38..3642fd16966 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/event/ServiceBeanExportEvent.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/event/ServiceBeanExportedEvent.java @@ -29,14 +29,14 @@ * @see ServiceBean * @since 2.6.4 */ -public class ServiceBeanExportEvent extends ApplicationEvent { +public class ServiceBeanExportedEvent extends ApplicationEvent { /** * Create a new ApplicationEvent. * * @param serviceBean {@link ServiceBean} bean */ - public ServiceBeanExportEvent(ServiceBean serviceBean) { + public ServiceBeanExportedEvent(ServiceBean serviceBean) { super(serviceBean); } From c0928d880579b66b90379bb9afd18db86b502f34 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Tue, 14 Aug 2018 18:46:47 +0800 Subject: [PATCH 16/38] Poblish apache/incubator-dubbo#2297 --- .../DubboConfigBindingRegistrar.java | 12 +-- .../properties/DefaultDubboConfigBinder.java | 4 +- .../spring/util/PropertySourcesUtils.java | 77 ----------------- .../spring/util/PropertySourcesUtilsTest.java | 84 ------------------- 4 files changed, 8 insertions(+), 169 deletions(-) delete mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java delete mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java index 6936787cc67..354a6c33d0f 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java @@ -40,8 +40,8 @@ import java.util.Map; import java.util.Set; -import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties; -import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.normalizePrefix; +import static com.alibaba.spring.util.PropertySourcesUtils.getSubProperties; +import static com.alibaba.spring.util.PropertySourcesUtils.normalizePrefix; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; import static org.springframework.beans.factory.support.BeanDefinitionReaderUtils.registerWithGeneratedName; @@ -85,7 +85,7 @@ private void registerDubboConfigBeans(String prefix, boolean multiple, BeanDefinitionRegistry registry) { - Map properties = getSubProperties(environment.getPropertySources(), prefix); + Map properties = getSubProperties(environment.getPropertySources(), prefix); if (CollectionUtils.isEmpty(properties)) { if (log.isDebugEnabled()) { @@ -157,7 +157,7 @@ public void setEnvironment(Environment environment) { } - private Set resolveMultipleBeanNames(Map properties) { + private Set resolveMultipleBeanNames(Map properties) { Set beanNames = new LinkedHashSet(); @@ -178,10 +178,10 @@ private Set resolveMultipleBeanNames(Map properties) { } - private String resolveSingleBeanName(Map properties, Class configClass, + private String resolveSingleBeanName(Map properties, Class configClass, BeanDefinitionRegistry registry) { - String beanName = properties.get("id"); + String beanName = (String) properties.get("id"); if (!StringUtils.hasText(beanName)) { BeanDefinitionBuilder builder = rootBeanDefinition(configClass); diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java index 52cc87ca4f5..129d1730ef2 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java @@ -22,7 +22,7 @@ import java.util.Map; -import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties; +import static com.alibaba.spring.util.PropertySourcesUtils.getSubProperties; /** * Default {@link DubboConfigBinder} implementation based on Spring {@link DataBinder} @@ -36,7 +36,7 @@ public void bind(String prefix, C dubboConfig) { dataBinder.setIgnoreInvalidFields(isIgnoreInvalidFields()); dataBinder.setIgnoreUnknownFields(isIgnoreUnknownFields()); // Get properties under specified prefix from PropertySources - Map properties = getSubProperties(getPropertySources(), prefix); + Map properties = getSubProperties(getPropertySources(), prefix); // Convert Map to MutablePropertyValues MutablePropertyValues propertyValues = new MutablePropertyValues(properties); // Bind diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java deleted file mode 100644 index a84e18ac819..00000000000 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java +++ /dev/null @@ -1,77 +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.util; - -import org.springframework.core.env.EnumerablePropertySource; -import org.springframework.core.env.PropertySource; -import org.springframework.core.env.PropertySources; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Properties; - -/** - * {@link PropertySources} Utilities - * - * @see PropertySources - * @since 2.5.8 - */ -public abstract class PropertySourcesUtils { - - /** - * Get Sub {@link Properties} - * - * @param propertySources {@link PropertySource} Iterable - * @param prefix the prefix of property name - * @return Map - * @see Properties - */ - public static Map getSubProperties(Iterable> propertySources, String prefix) { - - Map subProperties = new LinkedHashMap(); - - String normalizedPrefix = normalizePrefix(prefix); - - for (PropertySource source : propertySources) { - if (source instanceof EnumerablePropertySource) { - for (String name : ((EnumerablePropertySource) source).getPropertyNames()) { - if (name.startsWith(normalizedPrefix)) { - String subName = name.substring(normalizedPrefix.length()); - if (!subProperties.containsKey(subName)) { - Object value = source.getProperty(name); - subProperties.put(subName, String.valueOf(value)); - } - } - } - } - } - - return subProperties; - - } - - /** - * Normalize the prefix - * - * @param prefix the prefix - * @return the prefix - */ - public static String normalizePrefix(String prefix) { - return prefix.endsWith(".") ? prefix : prefix + "."; - } - -} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java deleted file mode 100644 index dddb6583a0b..00000000000 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java +++ /dev/null @@ -1,84 +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.util; - -import org.junit.Assert; -import org.junit.Test; -import org.springframework.core.env.MapPropertySource; -import org.springframework.core.env.MutablePropertySources; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -/** - * {@link PropertySourcesUtils} Test - * - * @see PropertySourcesUtils - * @since 2.5.8 - */ -public class PropertySourcesUtilsTest { - - @Test - public void testGetSubProperties() { - - MutablePropertySources propertySources = new MutablePropertySources(); - - Map source = new HashMap(); - - MapPropertySource propertySource = new MapPropertySource("test", source); - - propertySources.addFirst(propertySource); - - String KEY_PREFIX = "user"; - String KEY_NAME = "name"; - String KEY_AGE = "age"; - Map result = PropertySourcesUtils.getSubProperties(propertySources, KEY_PREFIX); - - Assert.assertEquals(Collections.emptyMap(), result); - - source.put(KEY_PREFIX + "." + KEY_NAME, "Mercy"); - source.put(KEY_PREFIX + "." + KEY_AGE, 31); - - Map expected = new HashMap(); - expected.put(KEY_NAME, "mercyblitz"); - expected.put(KEY_AGE, "31"); - - - Map source2 = new HashMap(); - - source2.put("user.name", "mercyblitz"); - - MapPropertySource propertySource2 = new MapPropertySource("test2", source2); - - propertySources.addFirst(propertySource2); - - - result = PropertySourcesUtils.getSubProperties(propertySources, KEY_PREFIX); - Assert.assertEquals(expected, result); - - result = PropertySourcesUtils.getSubProperties(propertySources, ""); - - Assert.assertEquals(Collections.emptyMap(), result); - - result = PropertySourcesUtils.getSubProperties(propertySources, "no-exists"); - - Assert.assertEquals(Collections.emptyMap(), result); - - } - -} From cba31b927220b98c3b44c58f066c209818b3a9cb Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Wed, 15 Aug 2018 08:57:54 +0800 Subject: [PATCH 17/38] Polish apache/incubator-dubbo#2301 --- .../annotation/ReferenceBeanBuilder.java | 46 ++++--- .../converter/StringArrayToMapConverter.java | 38 ------ .../StringArrayToStringConverter.java | 37 ------ .../annotation/ReferenceBeanBuilderTest.java | 124 ++++++++++++++++++ .../StringArrayToMapConverterTest.java | 52 -------- .../StringArrayToStringConverterTest.java | 46 ------- 6 files changed, 154 insertions(+), 189 deletions(-) delete mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToMapConverter.java delete mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToStringConverter.java create mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java delete mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToMapConverterTest.java delete mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/convert/converter/StringArrayToStringConverterTest.java 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 5d9418fbc8a..883a56a1879 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 @@ */ class ReferenceBeanBuilder extends AbstractAnnotationConfigBeanBuilder { + // 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 @@ protected ReferenceBean doBuild() { 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 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/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 56c6d4c4ccd..00000000000 --- 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> { - - @Override - public Map 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 23e948b0644..00000000000 --- 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 { - - @Override - public String convert(String[] source) { - return ObjectUtils.isEmpty(source) ? null : StringUtils.arrayToCommaDelimitedString(source); - } - -} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java new file mode 100644 index 00000000000..54b1b9741ea --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java @@ -0,0 +1,124 @@ +/* + * 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.spring.ReferenceBean; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; +import static org.springframework.util.ReflectionUtils.findField; + +/** + * {@link ReferenceBeanBuilder} Test + * + * @author Mercy + * @see ReferenceBeanBuilder + * @see Reference + * @since 2.6.4 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = ReferenceBeanBuilderTest.class) +public class ReferenceBeanBuilderTest { + + @Reference( + interfaceClass = CharSequence.class, + interfaceName = "java.lang.CharSequence", + version = "1.0.0", group = "TEST_GROUP", url = "dubbo://localhost:12345", + client = "client", generic = true, injvm = true, + check = false, init = false, lazy = true, + stubevent = true, reconnect = "reconnect", sticky = true, + proxy = "javassist", stub = "java.lang.CharSequence", cluster = "failover", + connections = 3, callbacks = 1, onconnect = "onconnect", ondisconnect = "ondisconnect", + owner = "owner", layer = "layer", retries = 1, + loadbalance = "random", async = true, actives = 3, + sent = true, mock = "mock", validation = "validation", + timeout = 3, cache = "cache", filter = {"echo", "generic", "accesslog"}, + listener = {"deprecated"}, parameters = {"n1=v1 ", "n2 = v2 ", " n3 = v3 "}, + application = "application", + module = "module", consumer = "consumer", monitor = "monitor", registry = {"registry"} + ) + private static final Object TEST_FIELD = new Object(); + + @Autowired + private ApplicationContext context; + + @Test + public void testBuild() throws Exception { + Reference reference = findAnnotation(findField(getClass(), "TEST_FIELD"), Reference.class); + ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder.create(reference, context.getClassLoader(), context); + beanBuilder.interfaceClass(CharSequence.class); + ReferenceBean referenceBean = beanBuilder.build(); + Assert.assertEquals(CharSequence.class, referenceBean.getInterfaceClass()); + Assert.assertEquals("1.0.0", referenceBean.getVersion()); + Assert.assertEquals("TEST_GROUP", referenceBean.getGroup()); + Assert.assertEquals("dubbo://localhost:12345", referenceBean.getUrl()); + Assert.assertEquals("client", referenceBean.getClient()); + Assert.assertEquals(true, referenceBean.isGeneric()); + Assert.assertEquals(true, referenceBean.isInjvm()); + Assert.assertEquals(false, referenceBean.isCheck()); + Assert.assertEquals(null, referenceBean.isInit()); + Assert.assertEquals(true, referenceBean.getLazy()); + Assert.assertEquals(true, referenceBean.getStubevent()); + Assert.assertEquals("reconnect", referenceBean.getReconnect()); + Assert.assertEquals(true, referenceBean.getSticky()); + Assert.assertEquals("javassist", referenceBean.getProxy()); + Assert.assertEquals("java.lang.CharSequence", referenceBean.getStub()); + Assert.assertEquals("failover", referenceBean.getCluster()); + Assert.assertEquals(Integer.valueOf(3), referenceBean.getConnections()); + Assert.assertEquals(Integer.valueOf(1), referenceBean.getCallbacks()); + Assert.assertEquals("onconnect", referenceBean.getOnconnect()); + Assert.assertEquals("ondisconnect", referenceBean.getOndisconnect()); + Assert.assertEquals("owner", referenceBean.getOwner()); + Assert.assertEquals("layer", referenceBean.getLayer()); + Assert.assertEquals(Integer.valueOf(1), referenceBean.getRetries()); + Assert.assertEquals("random", referenceBean.getLoadbalance()); + Assert.assertEquals(true, referenceBean.isAsync()); + Assert.assertEquals(Integer.valueOf(3), referenceBean.getActives()); + Assert.assertEquals(true, referenceBean.getSent()); + Assert.assertEquals("mock", referenceBean.getMock()); + Assert.assertEquals("validation", referenceBean.getValidation()); + Assert.assertEquals(Integer.valueOf(3), referenceBean.getTimeout()); + Assert.assertEquals("cache", referenceBean.getCache()); + Assert.assertEquals("echo,generic,accesslog", referenceBean.getFilter()); + Assert.assertEquals("deprecated", referenceBean.getListener()); + + // parameters + Map parameters = new HashMap(); + parameters.put("n1", "v1"); + parameters.put("n2", "v2"); + parameters.put("n3", "v3"); + Assert.assertEquals(parameters, referenceBean.getParameters()); + + // Asserts Null fields + Assert.assertNull(referenceBean.getApplication()); + Assert.assertNull(referenceBean.getModule()); + Assert.assertNull(referenceBean.getConsumer()); + Assert.assertNull(referenceBean.getMonitor()); + Assert.assertEquals(Collections.emptyList(), referenceBean.getRegistries()); + } +} 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 51be7c3f2f2..00000000000 --- 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 value = converter.convert(new String[]{"Hello", "World"}); - - Map expected = new LinkedHashMap(); - - 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 67e82479235..00000000000 --- 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); - - } - -} From 9d7fe246f7d2e2017dd48c13cfd74ba51e407145 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 17 Aug 2018 16:57:55 +0800 Subject: [PATCH 18/38] Polish apache/incubator-dubbo#2315 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 69aa46ede32..43a160c9b80 100644 --- a/pom.xml +++ b/pom.xml @@ -115,7 +115,7 @@ 2.8.2 3.6.0 3.0.1 - 3.0.0 + 3.0.1 6.1.26 3.0.0 0.8.1 From fa7130b757bdd605e15eb72e489197c9bce29256 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 7 Dec 2018 15:28:19 +0800 Subject: [PATCH 19/38] Polish apache/incubator-dubbo#2897 : DubboConfigConfigurationSelector precedence is too high --- .../DubboConfigConfigurationSelector.java | 34 +++++++++++++++---- .../annotation/EnableDubboConfigTest.java | 28 +++++++++++++++ 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java index 24f581b4d46..aa205fb9311 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java @@ -18,19 +18,29 @@ import com.alibaba.dubbo.config.AbstractConfig; +import org.springframework.context.EnvironmentAware; import org.springframework.context.annotation.ImportSelector; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotationMetadata; /** - * Dubbo {@link AbstractConfig Config} Registrar + * Dubbo {@link AbstractConfig Config} {@link ImportSelector} implementation, which order can be configured * * @see EnableDubboConfig * @see DubboConfigConfiguration + * @see Ordered * @since 2.5.8 */ -public class DubboConfigConfigurationSelector implements ImportSelector, Ordered { +public class DubboConfigConfigurationSelector implements ImportSelector, EnvironmentAware, Ordered { + + /** + * The property name of {@link EnableDubboConfig}'s {@link Ordered order} + */ + public static final String DUBBO_CONFIG_ORDER_PROPERTY_NAME = "dubbo.config.order"; + + private int order; @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { @@ -47,14 +57,26 @@ public String[] selectImports(AnnotationMetadata importingClassMetadata) { } } - private static T[] of(T... values) { - return values; + /** + * Set {@link Ordered order}, it may be changed in in the future. + * + * @param order {@link Ordered order} + */ + public void setOrder(int order) { + this.order = order; } @Override public int getOrder() { - return HIGHEST_PRECEDENCE; + return order; } + @Override + public void setEnvironment(Environment environment) { + this.order = environment.getProperty(DUBBO_CONFIG_ORDER_PROPERTY_NAME, int.class, LOWEST_PRECEDENCE); + } -} + private static T[] of(T... values) { + return values; + } +} \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java index d5c41b05bff..445cd2ba310 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java @@ -28,6 +28,14 @@ import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.StandardEnvironment; + +import java.util.HashMap; +import java.util.Map; + +import static com.alibaba.dubbo.config.spring.context.annotation.DubboConfigConfigurationSelector.DUBBO_CONFIG_ORDER_PROPERTY_NAME; /** * {@link EnableDubboConfig} Test @@ -36,6 +44,26 @@ */ public class EnableDubboConfigTest { + @Test + public void testOrder() { + Map source = new HashMap(); + source.put(DUBBO_CONFIG_ORDER_PROPERTY_NAME, "1"); + MapPropertySource propertySource = new MapPropertySource("test-property-source", source); + ConfigurableEnvironment environment = new StandardEnvironment(); + + environment.getPropertySources().addFirst(propertySource); + + DubboConfigConfigurationSelector selector = new DubboConfigConfigurationSelector(); + + selector.setEnvironment(environment); + + Assert.assertEquals(1, selector.getOrder()); + + selector.setOrder(2); + + Assert.assertEquals(2, selector.getOrder()); + } + @Test public void testSingle() { From b41ee81bf742dd2574e789f2aa423f891e773296 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 7 Dec 2018 16:04:43 +0800 Subject: [PATCH 20/38] Polish apache/incubator-dubbo#2897 : implements ImportBeanDefinitionRegistrar in order to reduce precedence --- .../DubboConfigConfigurationSelector.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java index aa205fb9311..d6e3f28f989 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java @@ -18,13 +18,17 @@ import com.alibaba.dubbo.config.AbstractConfig; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.EnvironmentAware; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.context.annotation.ImportSelector; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotationMetadata; +import static com.alibaba.spring.util.AnnotatedBeanDefinitionRegistryUtils.registerBeans; + /** * Dubbo {@link AbstractConfig Config} {@link ImportSelector} implementation, which order can be configured * @@ -33,7 +37,7 @@ * @see Ordered * @since 2.5.8 */ -public class DubboConfigConfigurationSelector implements ImportSelector, EnvironmentAware, Ordered { +public class DubboConfigConfigurationSelector implements ImportBeanDefinitionRegistrar, EnvironmentAware, Ordered { /** * The property name of {@link EnableDubboConfig}'s {@link Ordered order} @@ -43,7 +47,7 @@ public class DubboConfigConfigurationSelector implements ImportSelector, Environ private int order; @Override - public String[] selectImports(AnnotationMetadata importingClassMetadata) { + public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AnnotationAttributes attributes = AnnotationAttributes.fromMap( importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName())); @@ -51,9 +55,9 @@ public String[] selectImports(AnnotationMetadata importingClassMetadata) { boolean multiple = attributes.getBoolean("multiple"); if (multiple) { - return of(DubboConfigConfiguration.Multiple.class.getName()); + registerBeans(registry, DubboConfigConfiguration.Multiple.class); } else { - return of(DubboConfigConfiguration.Single.class.getName()); + registerBeans(registry, DubboConfigConfiguration.Single.class); } } @@ -79,4 +83,5 @@ public void setEnvironment(Environment environment) { private static T[] of(T... values) { return values; } + } \ No newline at end of file From b328a7d6dc9ad6733cf67b2c44a96632dc421de9 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 7 Dec 2018 16:06:20 +0800 Subject: [PATCH 21/38] Polish apache/incubator-dubbo#2897 : rename DubboConfigConfigurationSelector to DubboConfigConfigurationRegistrar --- ...nSelector.java => DubboConfigConfigurationRegistrar.java} | 5 ++--- .../config/spring/context/annotation/EnableDubboConfig.java | 4 ++-- .../spring/context/annotation/EnableDubboConfigTest.java | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) rename dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/{DubboConfigConfigurationSelector.java => DubboConfigConfigurationRegistrar.java} (90%) diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java similarity index 90% rename from dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java rename to dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java index d6e3f28f989..b18692bd12e 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java @@ -21,7 +21,6 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.EnvironmentAware; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; -import org.springframework.context.annotation.ImportSelector; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.env.Environment; @@ -30,14 +29,14 @@ import static com.alibaba.spring.util.AnnotatedBeanDefinitionRegistryUtils.registerBeans; /** - * Dubbo {@link AbstractConfig Config} {@link ImportSelector} implementation, which order can be configured + * Dubbo {@link AbstractConfig Config} {@link ImportBeanDefinitionRegistrar register}, which order can be configured * * @see EnableDubboConfig * @see DubboConfigConfiguration * @see Ordered * @since 2.5.8 */ -public class DubboConfigConfigurationSelector implements ImportBeanDefinitionRegistrar, EnvironmentAware, Ordered { +public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware, Ordered { /** * The property name of {@link EnableDubboConfig}'s {@link Ordered order} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfig.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfig.java index fe20770f228..8c70e114c4b 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfig.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfig.java @@ -59,14 +59,14 @@ * * @see EnableDubboConfigBinding * @see DubboConfigConfiguration - * @see DubboConfigConfigurationSelector + * @see DubboConfigConfigurationRegistrar * @since 2.5.8 */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented -@Import(DubboConfigConfigurationSelector.class) +@Import(DubboConfigConfigurationRegistrar.class) public @interface EnableDubboConfig { /** diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java index 445cd2ba310..f52f3af5fba 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java @@ -35,7 +35,7 @@ import java.util.HashMap; import java.util.Map; -import static com.alibaba.dubbo.config.spring.context.annotation.DubboConfigConfigurationSelector.DUBBO_CONFIG_ORDER_PROPERTY_NAME; +import static com.alibaba.dubbo.config.spring.context.annotation.DubboConfigConfigurationRegistrar.DUBBO_CONFIG_ORDER_PROPERTY_NAME; /** * {@link EnableDubboConfig} Test @@ -53,7 +53,7 @@ public void testOrder() { environment.getPropertySources().addFirst(propertySource); - DubboConfigConfigurationSelector selector = new DubboConfigConfigurationSelector(); + DubboConfigConfigurationRegistrar selector = new DubboConfigConfigurationRegistrar(); selector.setEnvironment(environment); From e7a843f5632406db7bb05032e41087861f4092f8 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Mon, 14 Jan 2019 16:08:18 +0800 Subject: [PATCH 22/38] Polish apache/incubator-dubbo#3192 : inline the source code of spring-context-support --- dubbo-config/dubbo-config-spring/pom.xml | 7 +- .../AbstractAnnotationConfigBeanBuilder.java | 4 +- .../AnnotationInjectedBeanPostProcessor.java | 529 ++++++++++++++++++ .../AnnotationPropertyValuesAdapter.java | 2 +- .../ReferenceAnnotationBeanPostProcessor.java | 3 +- .../annotation/ReferenceBeanBuilder.java | 4 +- .../ServiceAnnotationBeanPostProcessor.java | 2 +- .../DubboConfigBindingRegistrar.java | 4 +- .../DubboConfigConfigurationRegistrar.java | 3 +- .../properties/DefaultDubboConfigBinder.java | 2 +- .../extension/SpringExtensionFactory.java | 222 ++++---- .../status/DataSourceStatusChecker.java | 192 +++---- .../spring/status/SpringStatusChecker.java | 184 +++--- .../AnnotatedBeanDefinitionRegistryUtils.java | 62 ++ .../config/spring/util/AnnotationUtils.java | 214 ++++++- .../config/spring/util/BeanFactoryUtils.java | 63 ++- .../config/spring/util/BeanRegistrar.java | 2 +- .../dubbo/config/spring/util/ClassUtils.java | 37 ++ .../dubbo/config/spring/util/ObjectUtils.java | 37 ++ .../spring/util/PropertySourcesUtils.java | 112 ++++ ...otatedBeanDefinitionRegistryUtilsTest.java | 59 ++ .../spring/util/PropertySourcesUtilsTest.java | 80 +++ 22 files changed, 1505 insertions(+), 319 deletions(-) create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtils.java create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ClassUtils.java create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ObjectUtils.java create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java create mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtilsTest.java create mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java diff --git a/dubbo-config/dubbo-config-spring/pom.xml b/dubbo-config/dubbo-config-spring/pom.xml index 420140257a5..b73627870a1 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. --> - + 4.0.0 com.alibaba @@ -46,10 +47,6 @@ org.springframework spring-context - - com.alibaba.spring - spring-context-support - javax.servlet javax.servlet-api 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 7a4129f4563..0357ff0bc3e 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 @@ -30,8 +30,8 @@ import java.lang.annotation.Annotation; import java.util.List; -import static com.alibaba.spring.util.BeanFactoryUtils.getBeans; -import static com.alibaba.spring.util.BeanFactoryUtils.getOptionalBean; +import static com.alibaba.dubbo.config.spring.util.BeanFactoryUtils.getBeans; +import static com.alibaba.dubbo.config.spring.util.BeanFactoryUtils.getOptionalBean; /** * Abstract Configurable {@link Annotation} Bean Builder diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java new file mode 100644 index 00000000000..95ecdfb0a84 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java @@ -0,0 +1,529 @@ +/* + * 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 org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.BeanUtils; +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.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.annotation.InjectionMetadata; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +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.EnvironmentAware; +import org.springframework.core.Ordered; +import org.springframework.core.PriorityOrdered; +import org.springframework.core.env.Environment; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringUtils; + +import java.beans.PropertyDescriptor; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static com.alibaba.dubbo.config.spring.util.ClassUtils.resolveGenericType; +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; + +/** + * Abstract generic {@link BeanPostProcessor} implementation for customized annotation that annotated injected-object. + * + * The source code is cloned from https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java + * + * @since 2.6.6 + */ +public abstract class AnnotationInjectedBeanPostProcessor extends + InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, + BeanFactoryAware, BeanClassLoaderAware, EnvironmentAware, DisposableBean { + + private final static int CACHE_SIZE = Integer.getInteger("", 32); + + private final Log logger = LogFactory.getLog(getClass()); + + private final Class annotationType; + + private final ConcurrentMap injectionMetadataCache = + new ConcurrentHashMap(CACHE_SIZE); + + private final ConcurrentMap injectedObjectsCache = new ConcurrentHashMap(CACHE_SIZE); + + private ConfigurableListableBeanFactory beanFactory; + + private Environment environment; + + private ClassLoader classLoader; + + private int order = Ordered.LOWEST_PRECEDENCE; + + public AnnotationInjectedBeanPostProcessor() { + this.annotationType = resolveGenericType(getClass()); + } + + private static Collection combine(Collection... elements) { + List allElements = new ArrayList(); + for (Collection e : elements) { + allElements.addAll(e); + } + return allElements; + } + + /** + * Annotation type + * + * @return non-null + */ + public final Class getAnnotationType() { + return annotationType; + } + + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory, + "AnnotationInjectedBeanPostProcessor requires a ConfigurableListableBeanFactory"); + this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; + } + + @Override + public PropertyValues postProcessPropertyValues( + PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException { + + InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs); + try { + metadata.inject(bean, beanName, pvs); + } catch (BeanCreationException ex) { + throw ex; + } catch (Throwable ex) { + throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getName() + + " dependencies is failed", ex); + } + return pvs; + } + + + /** + * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link A} fields + * + * @param beanClass The {@link Class} of Bean + * @return non-null {@link List} + */ + private List findFieldAnnotationMetadata(final Class beanClass) { + + final List elements = new LinkedList(); + + ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() { + @Override + public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { + + A annotation = getAnnotation(field, getAnnotationType()); + + if (annotation != null) { + + if (Modifier.isStatic(field.getModifiers())) { + if (logger.isWarnEnabled()) { + logger.warn("@" + getAnnotationType().getName() + " is not supported on static fields: " + field); + } + return; + } + + elements.add(new AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement(field, annotation)); + } + + } + }); + + return elements; + + } + + /** + * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link A @A} methods + * + * @param beanClass The {@link Class} of Bean + * @return non-null {@link List} + */ + private List findAnnotatedMethodMetadata(final Class beanClass) { + + final List elements = new LinkedList(); + + ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() { + @Override + public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { + + Method bridgedMethod = findBridgedMethod(method); + + if (!isVisibilityBridgeMethodPair(method, bridgedMethod)) { + return; + } + + A annotation = findAnnotation(bridgedMethod, getAnnotationType()); + + if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) { + if (Modifier.isStatic(method.getModifiers())) { + if (logger.isWarnEnabled()) { + logger.warn("@" + getAnnotationType().getSimpleName() + " annotation is not supported on static methods: " + method); + } + return; + } + if (method.getParameterTypes().length == 0) { + if (logger.isWarnEnabled()) { + logger.warn("@" + getAnnotationType().getSimpleName() + " annotation should only be used on methods with parameters: " + + method); + } + } + PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass); + elements.add(new AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement(method, pd, annotation)); + } + } + }); + + return elements; + + } + + + private AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class beanClass) { + Collection fieldElements = findFieldAnnotationMetadata(beanClass); + Collection methodElements = findAnnotatedMethodMetadata(beanClass); + return new AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements); + + } + + private InjectionMetadata findInjectionMetadata(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. + AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata 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 = buildAnnotatedMetadata(clazz); + this.injectionMetadataCache.put(cacheKey, metadata); + } catch (NoClassDefFoundError err) { + throw new IllegalStateException("Failed to introspect object class [" + clazz.getName() + + "] for annotation metadata: could not find class that it depends on", err); + } + } + } + } + return metadata; + } + + @Override + public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) { + if (beanType != null) { + InjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null); + metadata.checkConfigMembers(beanDefinition); + } + } + + @Override + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + + @Override + public void destroy() throws Exception { + + for (Object object : injectedObjectsCache.values()) { + if (logger.isInfoEnabled()) { + logger.info(object + " was destroying!"); + } + + if (object instanceof DisposableBean) { + ((DisposableBean) object).destroy(); + } + } + + injectionMetadataCache.clear(); + injectedObjectsCache.clear(); + + if (logger.isInfoEnabled()) { + logger.info(getClass() + " was destroying!"); + } + + } + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + protected Environment getEnvironment() { + return environment; + } + + protected ClassLoader getClassLoader() { + return classLoader; + } + + protected ConfigurableListableBeanFactory getBeanFactory() { + return beanFactory; + } + + /** + * Gets all injected-objects. + * + * @return non-null {@link Collection} + */ + protected Collection getInjectedObjects() { + return this.injectedObjectsCache.values(); + } + + /** + * Get injected-object from specified {@link A annotation} and Bean Class + * + * @param annotation {@link A annotation} + * @param bean Current bean that will be injected + * @param beanName Current bean name that will be injected + * @param injectedType the type of injected-object + * @param injectedElement {@link InjectionMetadata.InjectedElement} + * @return An injected object + * @throws Exception If getting is failed + */ + protected Object getInjectedObject(A annotation, Object bean, String beanName, Class injectedType, + InjectionMetadata.InjectedElement injectedElement) throws Exception { + + String cacheKey = buildInjectedObjectCacheKey(annotation, bean, beanName, injectedType, injectedElement); + + Object injectedObject = injectedObjectsCache.get(cacheKey); + + if (injectedObject == null) { + injectedObject = doGetInjectedBean(annotation, bean, beanName, injectedType, injectedElement); + // Customized inject-object if necessary + injectedObjectsCache.putIfAbsent(cacheKey, injectedObject); + } + + return injectedObject; + + } + + /** + * Subclass must implement this method to get injected-object. The context objects could help this method if + * necessary : + *
    + *
  • {@link #getBeanFactory() BeanFactory}
  • + *
  • {@link #getClassLoader() ClassLoader}
  • + *
  • {@link #getEnvironment() Environment}
  • + *
+ * + * @param annotation {@link A annotation} + * @param bean Current bean that will be injected + * @param beanName Current bean name that will be injected + * @param injectedType the type of injected-object + * @param injectedElement {@link InjectionMetadata.InjectedElement} + * @return The injected object + * @throws Exception If resolving an injected object is failed. + */ + protected abstract Object doGetInjectedBean(A annotation, Object bean, String beanName, Class injectedType, + InjectionMetadata.InjectedElement injectedElement) throws Exception; + + /** + * Build a cache key for injected-object. The context objects could help this method if + * necessary : + *
    + *
  • {@link #getBeanFactory() BeanFactory}
  • + *
  • {@link #getClassLoader() ClassLoader}
  • + *
  • {@link #getEnvironment() Environment}
  • + *
+ * + * @param annotation {@link A annotation} + * @param bean Current bean that will be injected + * @param beanName Current bean name that will be injected + * @param injectedType the type of injected-object + * @param injectedElement {@link InjectionMetadata.InjectedElement} + * @return Bean cache key + */ + protected abstract String buildInjectedObjectCacheKey(A annotation, Object bean, String beanName, + Class injectedType, + InjectionMetadata.InjectedElement injectedElement); + + /** + * Get {@link Map} in injected field. + * + * @return non-null ready-only {@link Map} + */ + protected Map getInjectedFieldObjectsMap() { + + Map injectedElementBeanMap = + new LinkedHashMap(); + + for (AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata metadata : injectionMetadataCache.values()) { + + Collection fieldElements = metadata.getFieldElements(); + + for (AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement fieldElement : fieldElements) { + + injectedElementBeanMap.put(fieldElement, fieldElement.bean); + + } + + } + + return Collections.unmodifiableMap(injectedElementBeanMap); + + } + + /** + * Get {@link Map} in injected method. + * + * @return non-null {@link Map} + */ + protected Map getInjectedMethodObjectsMap() { + + Map injectedElementBeanMap = + new LinkedHashMap(); + + for (AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata metadata : injectionMetadataCache.values()) { + + Collection methodElements = metadata.getMethodElements(); + + for (AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement methodElement : methodElements) { + + injectedElementBeanMap.put(methodElement, methodElement.object); + + } + + } + + return Collections.unmodifiableMap(injectedElementBeanMap); + + } + + /** + * {@link A} {@link InjectionMetadata} implementation + */ + private class AnnotatedInjectionMetadata extends InjectionMetadata { + + private final Collection fieldElements; + + private final Collection methodElements; + + public AnnotatedInjectionMetadata(Class targetClass, Collection fieldElements, + Collection methodElements) { + super(targetClass, combine(fieldElements, methodElements)); + this.fieldElements = fieldElements; + this.methodElements = methodElements; + } + + public Collection getFieldElements() { + return fieldElements; + } + + public Collection getMethodElements() { + return methodElements; + } + } + + /** + * {@link A} {@link Method} {@link InjectionMetadata.InjectedElement} + */ + private class AnnotatedMethodElement extends InjectionMetadata.InjectedElement { + + private final Method method; + + private final A annotation; + + private volatile Object object; + + protected AnnotatedMethodElement(Method method, PropertyDescriptor pd, A annotation) { + super(method, pd); + this.method = method; + this.annotation = annotation; + } + + @Override + protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { + + Class injectedType = pd.getPropertyType(); + + Object injectedObject = getInjectedObject(annotation, bean, beanName, injectedType, this); + + ReflectionUtils.makeAccessible(method); + + method.invoke(bean, injectedObject); + + } + + } + + /** + * {@link A} {@link Field} {@link InjectionMetadata.InjectedElement} + */ + public class AnnotatedFieldElement extends InjectionMetadata.InjectedElement { + + private final Field field; + + private final A annotation; + + private volatile Object bean; + + protected AnnotatedFieldElement(Field field, A annotation) { + super(field, null); + this.field = field; + this.annotation = annotation; + } + + @Override + protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { + + Class injectedType = field.getType(); + + Object injectedObject = getInjectedObject(annotation, bean, beanName, injectedType, this); + + ReflectionUtils.makeAccessible(field); + + field.set(bean, injectedObject); + + } + + } +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapter.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapter.java index 29a8acc7eb5..aab1883a71e 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapter.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapter.java @@ -23,7 +23,7 @@ import java.lang.annotation.Annotation; -import static com.alibaba.spring.util.AnnotationUtils.getAttributes; +import static com.alibaba.dubbo.config.spring.util.AnnotationUtils.getAttributes; /** 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 517c62571ea..54c981e8103 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 @@ -20,8 +20,7 @@ import com.alibaba.dubbo.config.spring.ReferenceBean; 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 com.alibaba.spring.util.AnnotationUtils; +import com.alibaba.dubbo.config.spring.util.AnnotationUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.InjectionMetadata; 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 7b5288dfa9e..9b92d214169 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 @@ -31,8 +31,8 @@ import java.beans.PropertyEditorSupport; import java.util.Map; -import static com.alibaba.spring.util.BeanFactoryUtils.getOptionalBean; -import static com.alibaba.spring.util.ObjectUtils.of; +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; /** 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 d34b4a60e7f..b39d23f7da9 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 @@ -57,7 +57,7 @@ import java.util.List; import java.util.Set; -import static com.alibaba.spring.util.ObjectUtils.of; +import static com.alibaba.dubbo.config.spring.util.ObjectUtils.of; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; import static org.springframework.context.annotation.AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR; import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java index 8e8cf202f6e..5e1c18ef81a 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java @@ -41,8 +41,8 @@ import java.util.Map; import java.util.Set; -import static com.alibaba.spring.util.PropertySourcesUtils.getSubProperties; -import static com.alibaba.spring.util.PropertySourcesUtils.normalizePrefix; +import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties; +import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.normalizePrefix; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; import static org.springframework.beans.factory.support.BeanDefinitionReaderUtils.registerWithGeneratedName; diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java index b18692bd12e..fc292411db2 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java @@ -26,7 +26,8 @@ import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotationMetadata; -import static com.alibaba.spring.util.AnnotatedBeanDefinitionRegistryUtils.registerBeans; +import static com.alibaba.dubbo.config.spring.util.AnnotatedBeanDefinitionRegistryUtils.registerBeans; + /** * Dubbo {@link AbstractConfig Config} {@link ImportBeanDefinitionRegistrar register}, which order can be configured diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java index 045a5acbb6a..cda2a6eeff9 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java @@ -23,7 +23,7 @@ import java.util.Map; -import static com.alibaba.spring.util.PropertySourcesUtils.getSubProperties; +import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties; /** * Default {@link DubboConfigBinder} implementation based on Spring {@link DataBinder} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/extension/SpringExtensionFactory.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/extension/SpringExtensionFactory.java index 5cbc06e35af..c6a07de62d5 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/extension/SpringExtensionFactory.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/extension/SpringExtensionFactory.java @@ -1,111 +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.extension; - -import com.alibaba.dubbo.common.extension.ExtensionFactory; -import com.alibaba.dubbo.common.logger.Logger; -import com.alibaba.dubbo.common.logger.LoggerFactory; -import com.alibaba.dubbo.common.utils.ConcurrentHashSet; - -import com.alibaba.dubbo.config.DubboShutdownHook; -import com.alibaba.dubbo.config.spring.util.BeanFactoryUtils; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.beans.factory.NoUniqueBeanDefinitionException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextClosedEvent; - -import java.util.Set; - -/** - * SpringExtensionFactory - */ -public class SpringExtensionFactory implements ExtensionFactory { - private static final Logger logger = LoggerFactory.getLogger(SpringExtensionFactory.class); - - private static final Set contexts = new ConcurrentHashSet(); - - private static final ApplicationListener shutdownHookListener = new ShutdownHookListener(); - - public static void addApplicationContext(ApplicationContext context) { - contexts.add(context); - BeanFactoryUtils.addApplicationListener(context, shutdownHookListener); - } - - public static void removeApplicationContext(ApplicationContext context) { - contexts.remove(context); - } - - public static Set getContexts() { - return contexts; - } - - // currently for test purpose - public static void clearContexts() { - contexts.clear(); - } - - @Override - @SuppressWarnings("unchecked") - public T getExtension(Class type, String name) { - for (ApplicationContext context : contexts) { - if (context.containsBean(name)) { - Object bean = context.getBean(name); - if (type.isInstance(bean)) { - return (T) bean; - } - } - } - - logger.warn("No spring extension (bean) named:" + name + ", try to find an extension (bean) of type " + type.getName()); - - if (Object.class == type) { - return null; - } - - for (ApplicationContext context : contexts) { - try { - return context.getBean(type); - } catch (NoUniqueBeanDefinitionException multiBeanExe) { - logger.warn("Find more than 1 spring extensions (beans) of type " + type.getName() + ", will stop auto injection. Please make sure you have specified the concrete parameter type and there's only one extension of that type."); - } catch (NoSuchBeanDefinitionException noBeanExe) { - if (logger.isDebugEnabled()) { - logger.debug("Error when get spring extension(bean) for type:" + type.getName(), noBeanExe); - } - } - } - - logger.warn("No spring extension (bean) named:" + name + ", type:" + type.getName() + " found, stop get bean."); - - return null; - } - - private static class ShutdownHookListener implements ApplicationListener { - @Override - public void onApplicationEvent(ApplicationEvent event) { - if (event instanceof ContextClosedEvent) { - // we call it anyway since dubbo shutdown hook make sure its destroyAll() is re-entrant. - // pls. note we should not remove dubbo shutdown hook when spring framework is present, this is because - // its shutdown hook may not be installed. - DubboShutdownHook shutdownHook = DubboShutdownHook.getDubboShutdownHook(); - shutdownHook.destroyAll(); - } - } - } - -} +/* + * 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.extension; + +import com.alibaba.dubbo.common.extension.ExtensionFactory; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.ConcurrentHashSet; +import com.alibaba.dubbo.config.DubboShutdownHook; +import com.alibaba.dubbo.config.spring.util.BeanFactoryUtils; + +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.NoUniqueBeanDefinitionException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextClosedEvent; + +import java.util.Set; + +/** + * SpringExtensionFactory + */ +public class SpringExtensionFactory implements ExtensionFactory { + private static final Logger logger = LoggerFactory.getLogger(SpringExtensionFactory.class); + + private static final Set contexts = new ConcurrentHashSet(); + + private static final ApplicationListener shutdownHookListener = new ShutdownHookListener(); + + public static void addApplicationContext(ApplicationContext context) { + contexts.add(context); + BeanFactoryUtils.addApplicationListener(context, shutdownHookListener); + } + + public static void removeApplicationContext(ApplicationContext context) { + contexts.remove(context); + } + + public static Set getContexts() { + return contexts; + } + + // currently for test purpose + public static void clearContexts() { + contexts.clear(); + } + + @Override + @SuppressWarnings("unchecked") + public T getExtension(Class type, String name) { + for (ApplicationContext context : contexts) { + if (context.containsBean(name)) { + Object bean = context.getBean(name); + if (type.isInstance(bean)) { + return (T) bean; + } + } + } + + logger.warn("No spring extension (bean) named:" + name + ", try to find an extension (bean) of type " + type.getName()); + + if (Object.class == type) { + return null; + } + + for (ApplicationContext context : contexts) { + try { + return context.getBean(type); + } catch (NoUniqueBeanDefinitionException multiBeanExe) { + logger.warn("Find more than 1 spring extensions (beans) of type " + type.getName() + ", will stop auto injection. Please make sure you have specified the concrete parameter type and there's only one extension of that type."); + } catch (NoSuchBeanDefinitionException noBeanExe) { + if (logger.isDebugEnabled()) { + logger.debug("Error when get spring extension(bean) for type:" + type.getName(), noBeanExe); + } + } + } + + logger.warn("No spring extension (bean) named:" + name + ", type:" + type.getName() + " found, stop get bean."); + + return null; + } + + private static class ShutdownHookListener implements ApplicationListener { + @Override + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof ContextClosedEvent) { + // we call it anyway since dubbo shutdown hook make sure its destroyAll() is re-entrant. + // pls. note we should not remove dubbo shutdown hook when spring framework is present, this is because + // its shutdown hook may not be installed. + DubboShutdownHook shutdownHook = DubboShutdownHook.getDubboShutdownHook(); + shutdownHook.destroyAll(); + } + } + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusChecker.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusChecker.java index 32baa41da48..8863d8b2d6a 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusChecker.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/DataSourceStatusChecker.java @@ -1,96 +1,96 @@ -/* - * 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.status; - -import com.alibaba.dubbo.common.extension.Activate; -import com.alibaba.dubbo.common.logger.Logger; -import com.alibaba.dubbo.common.logger.LoggerFactory; -import com.alibaba.dubbo.common.status.Status; -import com.alibaba.dubbo.common.status.StatusChecker; - -import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory; -import org.springframework.context.ApplicationContext; - -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.ResultSet; -import java.util.Map; - -/** - * DataSourceStatusChecker - */ -@Activate -public class DataSourceStatusChecker implements StatusChecker { - - private static final Logger logger = LoggerFactory.getLogger(DataSourceStatusChecker.class); - - @Override - @SuppressWarnings("unchecked") - public Status check() { - ApplicationContext context = null; - for (ApplicationContext c : SpringExtensionFactory.getContexts()) { - if (c != null) { - context = c; - break; - } - } - if (context == null) { - return new Status(Status.Level.UNKNOWN); - } - Map dataSources = context.getBeansOfType(DataSource.class, false, false); - if (dataSources == null || dataSources.size() == 0) { - return new Status(Status.Level.UNKNOWN); - } - Status.Level level = Status.Level.OK; - StringBuilder buf = new StringBuilder(); - for (Map.Entry entry : dataSources.entrySet()) { - DataSource dataSource = entry.getValue(); - if (buf.length() > 0) { - buf.append(", "); - } - buf.append(entry.getKey()); - try { - Connection connection = dataSource.getConnection(); - try { - DatabaseMetaData metaData = connection.getMetaData(); - ResultSet resultSet = metaData.getTypeInfo(); - try { - if (!resultSet.next()) { - level = Status.Level.ERROR; - } - } finally { - resultSet.close(); - } - buf.append(metaData.getURL()); - buf.append("("); - buf.append(metaData.getDatabaseProductName()); - buf.append("-"); - buf.append(metaData.getDatabaseProductVersion()); - buf.append(")"); - } finally { - connection.close(); - } - } catch (Throwable e) { - logger.warn(e.getMessage(), e); - return new Status(level, e.getMessage()); - } - } - return new Status(level, buf.toString()); - } - -} +/* + * 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.status; + +import com.alibaba.dubbo.common.extension.Activate; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.status.Status; +import com.alibaba.dubbo.common.status.StatusChecker; +import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory; + +import org.springframework.context.ApplicationContext; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.util.Map; + +/** + * DataSourceStatusChecker + */ +@Activate +public class DataSourceStatusChecker implements StatusChecker { + + private static final Logger logger = LoggerFactory.getLogger(DataSourceStatusChecker.class); + + @Override + @SuppressWarnings("unchecked") + public Status check() { + ApplicationContext context = null; + for (ApplicationContext c : SpringExtensionFactory.getContexts()) { + if (c != null) { + context = c; + break; + } + } + if (context == null) { + return new Status(Status.Level.UNKNOWN); + } + Map dataSources = context.getBeansOfType(DataSource.class, false, false); + if (dataSources == null || dataSources.size() == 0) { + return new Status(Status.Level.UNKNOWN); + } + Status.Level level = Status.Level.OK; + StringBuilder buf = new StringBuilder(); + for (Map.Entry entry : dataSources.entrySet()) { + DataSource dataSource = entry.getValue(); + if (buf.length() > 0) { + buf.append(", "); + } + buf.append(entry.getKey()); + try { + Connection connection = dataSource.getConnection(); + try { + DatabaseMetaData metaData = connection.getMetaData(); + ResultSet resultSet = metaData.getTypeInfo(); + try { + if (!resultSet.next()) { + level = Status.Level.ERROR; + } + } finally { + resultSet.close(); + } + buf.append(metaData.getURL()); + buf.append("("); + buf.append(metaData.getDatabaseProductName()); + buf.append("-"); + buf.append(metaData.getDatabaseProductVersion()); + buf.append(")"); + } finally { + connection.close(); + } + } catch (Throwable e) { + logger.warn(e.getMessage(), e); + return new Status(level, e.getMessage()); + } + } + return new Status(level, buf.toString()); + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/SpringStatusChecker.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/SpringStatusChecker.java index f80b5e6b806..282f3644fc3 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/SpringStatusChecker.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/status/SpringStatusChecker.java @@ -1,92 +1,92 @@ -/* - * 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.status; - -import com.alibaba.dubbo.common.extension.Activate; -import com.alibaba.dubbo.common.logger.Logger; -import com.alibaba.dubbo.common.logger.LoggerFactory; -import com.alibaba.dubbo.common.status.Status; -import com.alibaba.dubbo.common.status.StatusChecker; - -import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory; -import org.springframework.context.ApplicationContext; -import org.springframework.context.Lifecycle; - -import java.lang.reflect.Method; - -/** - * SpringStatusChecker - */ -@Activate -public class SpringStatusChecker implements StatusChecker { - - private static final Logger logger = LoggerFactory.getLogger(SpringStatusChecker.class); - - @Override - public Status check() { - ApplicationContext context = null; - for (ApplicationContext c : SpringExtensionFactory.getContexts()) { - if (c != null) { - context = c; - break; - } - } - if (context == null) { - return new Status(Status.Level.UNKNOWN); - } - Status.Level level = Status.Level.OK; - if (context instanceof Lifecycle) { - if (((Lifecycle) context).isRunning()) { - level = Status.Level.OK; - } else { - level = Status.Level.ERROR; - } - } else { - level = Status.Level.UNKNOWN; - } - StringBuilder buf = new StringBuilder(); - try { - Class cls = context.getClass(); - Method method = null; - while (cls != null && method == null) { - try { - method = cls.getDeclaredMethod("getConfigLocations", new Class[0]); - } catch (NoSuchMethodException t) { - cls = cls.getSuperclass(); - } - } - if (method != null) { - if (!method.isAccessible()) { - method.setAccessible(true); - } - String[] configs = (String[]) method.invoke(context, new Object[0]); - if (configs != null && configs.length > 0) { - for (String config : configs) { - if (buf.length() > 0) { - buf.append(","); - } - buf.append(config); - } - } - } - } catch (Throwable t) { - logger.warn(t.getMessage(), t); - } - return new Status(level, buf.toString()); - } - -} +/* + * 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.status; + +import com.alibaba.dubbo.common.extension.Activate; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.status.Status; +import com.alibaba.dubbo.common.status.StatusChecker; +import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.Lifecycle; + +import java.lang.reflect.Method; + +/** + * SpringStatusChecker + */ +@Activate +public class SpringStatusChecker implements StatusChecker { + + private static final Logger logger = LoggerFactory.getLogger(SpringStatusChecker.class); + + @Override + public Status check() { + ApplicationContext context = null; + for (ApplicationContext c : SpringExtensionFactory.getContexts()) { + if (c != null) { + context = c; + break; + } + } + if (context == null) { + return new Status(Status.Level.UNKNOWN); + } + Status.Level level = Status.Level.OK; + if (context instanceof Lifecycle) { + if (((Lifecycle) context).isRunning()) { + level = Status.Level.OK; + } else { + level = Status.Level.ERROR; + } + } else { + level = Status.Level.UNKNOWN; + } + StringBuilder buf = new StringBuilder(); + try { + Class cls = context.getClass(); + Method method = null; + while (cls != null && method == null) { + try { + method = cls.getDeclaredMethod("getConfigLocations", new Class[0]); + } catch (NoSuchMethodException t) { + cls = cls.getSuperclass(); + } + } + if (method != null) { + if (!method.isAccessible()) { + method.setAccessible(true); + } + String[] configs = (String[]) method.invoke(context, new Object[0]); + if (configs != null && configs.length > 0) { + for (String config : configs) { + if (buf.length() > 0) { + buf.append(","); + } + buf.append(config); + } + } + } + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + return new Status(level, buf.toString()); + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtils.java new file mode 100644 index 00000000000..ccc34272a86 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtils.java @@ -0,0 +1,62 @@ +/* + * 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.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; +import org.springframework.util.ObjectUtils; + +import java.lang.annotation.Annotation; +import java.util.Arrays; + +/** + * Annotated {@link BeanDefinition} Utilities + *

+ * The source code is cloned from https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/AnnotatedBeanDefinitionRegistryUtils.java + * @since 2.6.6 + */ +public abstract class AnnotatedBeanDefinitionRegistryUtils { + + private static final Log logger = LogFactory.getLog(AnnotatedBeanDefinitionRegistryUtils.class); + + /** + * Register Beans + * + * @param registry {@link BeanDefinitionRegistry} + * @param annotatedClasses {@link Annotation annotation} class + */ + public static void registerBeans(BeanDefinitionRegistry registry, Class... annotatedClasses) { + + if (ObjectUtils.isEmpty(annotatedClasses)) { + return; + } + + boolean debugEnabled = logger.isDebugEnabled(); + + AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry); + + if (debugEnabled) { + logger.debug(registry.getClass().getSimpleName() + " will register annotated classes : " + Arrays.asList(annotatedClasses) + " ."); + } + + reader.register(annotatedClasses); + + } +} 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 7e5bb498d0b..703e649ad23 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 @@ -19,15 +19,39 @@ import com.alibaba.dubbo.config.annotation.Reference; import com.alibaba.dubbo.config.annotation.Service; +import org.springframework.core.env.Environment; +import org.springframework.core.env.PropertyResolver; import org.springframework.util.StringUtils; +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static java.lang.String.valueOf; +import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; +import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes; +import static org.springframework.core.annotation.AnnotationUtils.getDefaultValue; +import static org.springframework.util.CollectionUtils.arrayToList; +import static org.springframework.util.ObjectUtils.nullSafeEquals; +import static org.springframework.util.StringUtils.trimWhitespace; + /** * Annotation Utilities Class * * @see org.springframework.core.annotation.AnnotationUtils * @since 2.5.11 */ -public class AnnotationUtils { +public abstract class AnnotationUtils { public static String resolveInterfaceName(Service service, Class defaultInterfaceClass) throws IllegalStateException { @@ -69,4 +93,192 @@ public static String resolveInterfaceName(Reference reference, Class defaultI } + + // Cloned from https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/AnnotationUtils.java + + /** + * Is specified {@link Annotation} present on {@link Method}'s declaring class or parameters or itself. + * + * @param method {@link Method} + * @param annotationClass {@link Annotation} type + * @param {@link Annotation} type + * @return If present , return true , or false + * @since 2.6.6 + */ + public static boolean isPresent(Method method, Class annotationClass) { + + Map> annotationsMap = findAnnotations(method, annotationClass); + + return !annotationsMap.isEmpty(); + + } + + /** + * Find specified {@link Annotation} type maps from {@link Method} + * + * @param method {@link Method} + * @param annotationClass {@link Annotation} type + * @param {@link Annotation} type + * @return {@link Annotation} type maps , the {@link ElementType} as key , + * the list of {@link Annotation} as value. + * If {@link Annotation} was annotated on {@link Method}'s parameters{@link ElementType#PARAMETER} , + * the associated {@link Annotation} list may contain multiple elements. + * @since 2.6.6 + */ + public static Map> findAnnotations(Method method, + Class annotationClass) { + + Retention retention = annotationClass.getAnnotation(Retention.class); + + RetentionPolicy retentionPolicy = retention.value(); + + if (!RetentionPolicy.RUNTIME.equals(retentionPolicy)) { + return Collections.emptyMap(); + } + + Map> annotationsMap = new LinkedHashMap>(); + + Target target = annotationClass.getAnnotation(Target.class); + + ElementType[] elementTypes = target.value(); + + + for (ElementType elementType : elementTypes) { + + List annotationsList = new LinkedList(); + + switch (elementType) { + + case PARAMETER: + + Annotation[][] parameterAnnotations = method.getParameterAnnotations(); + + for (Annotation[] annotations : parameterAnnotations) { + + for (Annotation annotation : annotations) { + + if (annotationClass.equals(annotation.annotationType())) { + + annotationsList.add((A) annotation); + + } + + } + + } + + break; + + case METHOD: + + A annotation = findAnnotation(method, annotationClass); + + if (annotation != null) { + + annotationsList.add(annotation); + + } + + break; + + case TYPE: + + Class beanType = method.getDeclaringClass(); + + A annotation2 = findAnnotation(beanType, annotationClass); + + if (annotation2 != null) { + + annotationsList.add(annotation2); + + } + + break; + + } + + if (!annotationsList.isEmpty()) { + + annotationsMap.put(elementType, annotationsList); + + } + + + } + + return Collections.unmodifiableMap(annotationsMap); + + } + + /** + * Get the {@link Annotation} attributes + * + * @param annotation specified {@link Annotation} + * @param ignoreDefaultValue whether ignore default value or not + * @param ignoreAttributeNames the attribute names of annotation should be ignored + * @return non-null + * @since 2.6.6 + */ + public static Map getAttributes(Annotation annotation, boolean ignoreDefaultValue, + String... ignoreAttributeNames) { + return getAttributes(annotation, null, ignoreDefaultValue, ignoreAttributeNames); + } + + /** + * Get the {@link Annotation} attributes + * + * @param annotation specified {@link Annotation} + * @param propertyResolver {@link PropertyResolver} instance, e.g {@link Environment} + * @param ignoreDefaultValue whether ignore default value or not + * @param ignoreAttributeNames the attribute names of annotation should be ignored + * @return non-null + * @since 2.6.6 + */ + public static Map getAttributes(Annotation annotation, PropertyResolver propertyResolver, + boolean ignoreDefaultValue, String... ignoreAttributeNames) { + + Set ignoreAttributeNamesSet = new HashSet(arrayToList(ignoreAttributeNames)); + + Map attributes = getAnnotationAttributes(annotation); + + Map actualAttributes = new LinkedHashMap(); + + for (Map.Entry entry : attributes.entrySet()) { + + String attributeName = entry.getKey(); + Object attributeValue = entry.getValue(); + + // ignore default attribute value + if (ignoreDefaultValue && nullSafeEquals(attributeValue, getDefaultValue(annotation, attributeName))) { + continue; + } + + // ignore attribute name + if (ignoreAttributeNamesSet.contains(attributeName)) { + continue; + } + + if (attributeValue instanceof String) { + attributeValue = resolvePlaceholders(valueOf(attributeValue), propertyResolver); + } else if (attributeValue instanceof String[]) { + String[] values = (String[]) attributeValue; + for (int i = 0; i < values.length; i++) { + values[i] = resolvePlaceholders(values[i], propertyResolver); + } + attributeValue = values; + } + actualAttributes.put(attributeName, attributeValue); + } + return actualAttributes; + } + + private static String resolvePlaceholders(String attributeValue, PropertyResolver propertyResolver) { + String resolvedValue = attributeValue; + if (propertyResolver != null) { + resolvedValue = propertyResolver.resolvePlaceholders(resolvedValue); + resolvedValue = trimWhitespace(resolvedValue); + } + return resolvedValue; + } + } \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanFactoryUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanFactoryUtils.java index 13a3011c0d8..9018fddde5d 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanFactoryUtils.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanFactoryUtils.java @@ -17,12 +17,21 @@ package com.alibaba.dubbo.config.spring.util; import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationListener; import org.springframework.context.support.AbstractApplicationContext; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static org.springframework.beans.factory.BeanFactoryUtils.beanNamesForTypeIncludingAncestors; +import static org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors; +import static org.springframework.util.ObjectUtils.containsElement; /** * {@link BeanFactory} Utilities class @@ -31,7 +40,8 @@ * @see ConfigurableBeanFactory * @see org.springframework.beans.factory.BeanFactoryUtils */ -public class BeanFactoryUtils { +public abstract class BeanFactoryUtils { + public static boolean addApplicationListener(ApplicationContext applicationContext, ApplicationListener listener) { try { // backward compatibility to spring 2.0.1 @@ -55,4 +65,55 @@ public static boolean addApplicationListener(ApplicationContext applicationConte } return false; } + + /** + * Get optional Bean + * + * @param beanFactory {@link ListableBeanFactory} + * @param beanName the name of Bean + * @param beanType the {@link Class type} of Bean + * @param the {@link Class type} of Bean + * @return A bean if present , or null + * @since 2.6.6 + */ + public static T getOptionalBean(ListableBeanFactory beanFactory, String beanName, Class beanType) { + + String[] allBeanNames = beanNamesForTypeIncludingAncestors(beanFactory, beanType); + + if (!containsElement(allBeanNames, beanName)) { + return null; + } + + Map beansOfType = beansOfTypeIncludingAncestors(beanFactory, beanType); + + return beansOfType.get(beanName); + + } + + + /** + * Gets name-matched Beans from {@link ListableBeanFactory BeanFactory} + * + * @param beanFactory {@link ListableBeanFactory BeanFactory} + * @param beanNames the names of Bean + * @param beanType the {@link Class type} of Bean + * @param the {@link Class type} of Bean + * @return the read-only and non-null {@link List} of Bean names + * @since 2.6.6 + */ + public static List getBeans(ListableBeanFactory beanFactory, String[] beanNames, Class beanType) { + + String[] allBeanNames = beanNamesForTypeIncludingAncestors(beanFactory, beanType); + + List beans = new ArrayList(beanNames.length); + + for (String beanName : beanNames) { + if (containsElement(allBeanNames, beanName)) { + beans.add(beanFactory.getBean(beanName, beanType)); + } + } + + return Collections.unmodifiableList(beans); + } + } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanRegistrar.java index 671d63f277b..08a13acaa66 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanRegistrar.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanRegistrar.java @@ -25,7 +25,7 @@ * * @since 2.5.7 */ -public class BeanRegistrar { +public abstract class BeanRegistrar { /** * Register Infrastructure Bean diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ClassUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ClassUtils.java new file mode 100644 index 00000000000..6bb1d81d417 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ClassUtils.java @@ -0,0 +1,37 @@ +/* + * 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.util; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +/** + * {@link Class} Utilities + *

+ * The source code is cloned from + * https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/ClassUtils.java + * + * @since 2.6.6 + */ +public abstract class ClassUtils { + + public static Class resolveGenericType(Class declaredClass) { + ParameterizedType parameterizedType = (ParameterizedType) declaredClass.getGenericSuperclass(); + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + return (Class) actualTypeArguments[0]; + } +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ObjectUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ObjectUtils.java new file mode 100644 index 00000000000..abb981febd1 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ObjectUtils.java @@ -0,0 +1,37 @@ +/* + * 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.util; + +/** + * Object Utilities + * + * @since 2.6.6 + */ +public abstract class ObjectUtils { + + /** + * Convert from variable arguments to array + * + * @param values variable arguments + * @param The class + * @return array + */ + public static T[] of(T... values) { + return values; + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java new file mode 100644 index 00000000000..06c707781d7 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java @@ -0,0 +1,112 @@ +/* + * 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.util; + +import org.springframework.core.env.AbstractEnvironment; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.env.PropertySource; +import org.springframework.core.env.PropertySources; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; + + +/** + * {@link PropertySources} Utilities + *

+ * The source code is cloned from https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/PropertySourcesUtils.java + * + * @since 2.6.6 + */ +public abstract class PropertySourcesUtils { + + /** + * Get Sub {@link Properties} + * + * @param propertySources {@link PropertySource} Iterable + * @param prefix the prefix of property name + * @return Map + * @see Properties + */ + public static Map getSubProperties(Iterable> propertySources, String prefix) { + + // Non-Extension AbstractEnvironment + AbstractEnvironment environment = new AbstractEnvironment() { + }; + + MutablePropertySources mutablePropertySources = environment.getPropertySources(); + + for (PropertySource source : propertySources) { + mutablePropertySources.addLast(source); + } + + return getSubProperties(environment, prefix); + + } + + /** + * Get Sub {@link Properties} + * + * @param environment {@link ConfigurableEnvironment} + * @param prefix the prefix of property name + * @return Map + * @see Properties + */ + public static Map getSubProperties(ConfigurableEnvironment environment, String prefix) { + + Map subProperties = new LinkedHashMap(); + + MutablePropertySources propertySources = environment.getPropertySources(); + + String normalizedPrefix = normalizePrefix(prefix); + + for (PropertySource source : propertySources) { + if (source instanceof EnumerablePropertySource) { + for (String name : ((EnumerablePropertySource) source).getPropertyNames()) { + if (!subProperties.containsKey(name) && name.startsWith(normalizedPrefix)) { + String subName = name.substring(normalizedPrefix.length()); + if (!subProperties.containsKey(subName)) { // take first one + Object value = source.getProperty(name); + if (value instanceof String) { + // Resolve placeholder + value = environment.resolvePlaceholders((String) value); + } + subProperties.put(subName, value); + } + } + } + } + } + + return Collections.unmodifiableMap(subProperties); + + } + + /** + * Normalize the prefix + * + * @param prefix the prefix + * @return the prefix + */ + public static String normalizePrefix(String prefix) { + return prefix.endsWith(".") ? prefix : prefix + "."; + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtilsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtilsTest.java new file mode 100644 index 00000000000..c54fa9feb8a --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtilsTest.java @@ -0,0 +1,59 @@ +/* + * 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.util; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.context.annotation.AnnotationConfigUtils; +import org.springframework.util.ObjectUtils; + +/** + * {@link AnnotatedBeanDefinitionRegistryUtils} Test + * + * @see AnnotatedBeanDefinitionRegistryUtils + * @since 2.6.6 + */ +public class AnnotatedBeanDefinitionRegistryUtilsTest { + + private DefaultListableBeanFactory registry = null; + + @Before + public void init() { + registry = new DefaultListableBeanFactory(); + AnnotationConfigUtils.registerAnnotationConfigProcessors(registry); + } + + @Test + public void testRegisterBeans() { + + AnnotatedBeanDefinitionRegistryUtils.registerBeans(registry, this.getClass()); + + String[] beanNames = registry.getBeanNamesForType(this.getClass()); + + Assert.assertEquals(1, beanNames.length); + + beanNames = registry.getBeanNamesForType(AnnotatedBeanDefinitionRegistryUtils.class); + + Assert.assertTrue(ObjectUtils.isEmpty(beanNames)); + + AnnotatedBeanDefinitionRegistryUtils.registerBeans(registry); + + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java new file mode 100644 index 00000000000..4a17ac1c7b2 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java @@ -0,0 +1,80 @@ +/* + * 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.util; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.MutablePropertySources; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * {@link PropertySourcesUtils} Test + * + * @author Mercy + * @see PropertySourcesUtils + * @since 2.6.6 + */ +public class PropertySourcesUtilsTest { + + @Test + public void testGetSubProperties() { + + MutablePropertySources propertySources = new MutablePropertySources(); + + Map source = new HashMap(); + Map source2 = new HashMap(); + + MapPropertySource propertySource = new MapPropertySource("propertySource", source); + MapPropertySource propertySource2 = new MapPropertySource("propertySource2", source2); + + propertySources.addLast(propertySource); + propertySources.addLast(propertySource2); + + Map result = PropertySourcesUtils.getSubProperties(propertySources, "user"); + + Assert.assertEquals(Collections.emptyMap(), result); + + source.put("age", "31"); + source.put("user.name", "Mercy"); + source.put("user.age", "${age}"); + + source2.put("user.name", "mercyblitz"); + source2.put("user.age", "32"); + + Map expected = new HashMap(); + expected.put("name", "Mercy"); + expected.put("age", "31"); + + result = PropertySourcesUtils.getSubProperties(propertySources, "user"); + + Assert.assertEquals(expected, result); + + result = PropertySourcesUtils.getSubProperties(propertySources, ""); + + Assert.assertEquals(Collections.emptyMap(), result); + + result = PropertySourcesUtils.getSubProperties(propertySources, "no-exists"); + + Assert.assertEquals(Collections.emptyMap(), result); + + } + +} From 143b342fc1cc0a425945f6758b52b940eb9b57a6 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Tue, 15 Jan 2019 15:43:41 +0800 Subject: [PATCH 23/38] Fixed the issues of the test-cases --- .../annotation/ReferenceAnnotationBeanPostProcessorTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 a48a85eb75c..0003d699211 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 @@ -124,7 +124,7 @@ public void testGetInjectedFieldReferenceBeanMap() { InjectionMetadata.InjectedElement injectedElement = entry.getKey(); - Assert.assertEquals("com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedFieldElement", + Assert.assertEquals("com.alibaba.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedFieldElement", injectedElement.getClass().getName()); ReferenceBean referenceBean = entry.getValue(); @@ -152,7 +152,7 @@ public void testGetInjectedMethodReferenceBeanMap() { InjectionMetadata.InjectedElement injectedElement = entry.getKey(); - Assert.assertEquals("com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedMethodElement", + Assert.assertEquals("com.alibaba.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedMethodElement", injectedElement.getClass().getName()); ReferenceBean referenceBean = entry.getValue(); From 989963edc4eb60ae386ec721c4f446a6419d40a1 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Wed, 16 Jan 2019 13:19:23 +0800 Subject: [PATCH 24/38] Polish apache/incubator-dubbo#3193 : [Enhancement] Change the default behavior of @EnableDubboConfig.multiple() --- .../DubboConfigConfigurationRegistrar.java | 44 +++---------------- .../context/annotation/EnableDubboConfig.java | 9 ++-- .../DubboConfigBindingRegistrarTest.java | 14 +++++- .../DubboConfigBindingsRegistrarTest.java | 2 +- .../DubboConfigConfigurationTest.java | 4 +- .../annotation/EnableDubboConfigTest.java | 44 +++++++------------ .../test/resources/META-INF/config.properties | 2 +- 7 files changed, 44 insertions(+), 75 deletions(-) diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java index fc292411db2..ff20d8dfd5f 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java @@ -19,32 +19,23 @@ import com.alibaba.dubbo.config.AbstractConfig; import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.context.EnvironmentAware; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationAttributes; -import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotationMetadata; import static com.alibaba.dubbo.config.spring.util.AnnotatedBeanDefinitionRegistryUtils.registerBeans; /** - * Dubbo {@link AbstractConfig Config} {@link ImportBeanDefinitionRegistrar register}, which order can be configured + * Dubbo {@link AbstractConfig Config} {@link ImportBeanDefinitionRegistrar register} * * @see EnableDubboConfig * @see DubboConfigConfiguration * @see Ordered * @since 2.5.8 */ -public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware, Ordered { - - /** - * The property name of {@link EnableDubboConfig}'s {@link Ordered order} - */ - public static final String DUBBO_CONFIG_ORDER_PROPERTY_NAME = "dubbo.config.order"; - - private int order; +public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { @@ -54,34 +45,11 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B boolean multiple = attributes.getBoolean("multiple"); - if (multiple) { + // Single Config Bindings + registerBeans(registry, DubboConfigConfiguration.Single.class); + + if (multiple) { // Since 2.6.6 https://github.com/apache/incubator-dubbo/issues/3193 registerBeans(registry, DubboConfigConfiguration.Multiple.class); - } else { - registerBeans(registry, DubboConfigConfiguration.Single.class); } } - - /** - * Set {@link Ordered order}, it may be changed in in the future. - * - * @param order {@link Ordered order} - */ - public void setOrder(int order) { - this.order = order; - } - - @Override - public int getOrder() { - return order; - } - - @Override - public void setEnvironment(Environment environment) { - this.order = environment.getProperty(DUBBO_CONFIG_ORDER_PROPERTY_NAME, int.class, LOWEST_PRECEDENCE); - } - - private static T[] of(T... values) { - return values; - } - } \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfig.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfig.java index 8c70e114c4b..ad394f7f093 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfig.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfig.java @@ -46,7 +46,7 @@ *

  • {@link ConsumerConfig} binding to property : "dubbo.consumer"
  • * *

    - * In contrast, on multiple bean bindings that requires to set {@link #multiple()} to be true : + * On multiple bean bindings that requires to set {@link #multiple()} to be true : *

      *
    • {@link ApplicationConfig} binding to property : "dubbo.applications"
    • *
    • {@link ModuleConfig} binding to property : "dubbo.modules"
    • @@ -71,10 +71,13 @@ /** * It indicates whether binding to multiple Spring Beans. + *

      + * Please note that if {@link #multiple()} is true since 2.6.6, the multiple bean bindings will be + * enabled, works with single bean bindings, rather than they are mutually exclusive before. * - * @return the default value is false + * @return the default value is true since 2.6.6, the value is inverse earlier. * @revised 2.5.9 */ - boolean multiple() default false; + boolean multiple() default true; } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrarTest.java index 853df842ba8..30fc54a6708 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrarTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrarTest.java @@ -23,6 +23,11 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.PropertySource; +import java.util.Set; +import java.util.TreeSet; + +import static java.util.Arrays.asList; + /** * {@link DubboConfigBindingRegistrar} * @@ -55,9 +60,14 @@ public void testRegisterBeanDefinitionsForMultiple() { context.refresh(); - ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); + Set expectedBeanNames = new TreeSet(asList("applicationBean1", "applicationBean2", "applicationBean3")); + Set actualBeanNames = new TreeSet(asList(context.getBeanNamesForType(ApplicationConfig.class))); - Assert.assertEquals("dubbo-demo-application", applicationConfig.getName()); + Assert.assertEquals(expectedBeanNames, actualBeanNames); + + ApplicationConfig applicationConfig = context.getBean("applicationBean1", ApplicationConfig.class); + + Assert.assertEquals("dubbo-demo-application1", applicationConfig.getName()); applicationConfig = context.getBean("applicationBean2", ApplicationConfig.class); diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java index a73dbf2c62a..b871983fb70 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java @@ -50,7 +50,7 @@ public void test() { @EnableDubboConfigBindings({ @EnableDubboConfigBinding(prefix = "${application.prefix}", type = ApplicationConfig.class), - @EnableDubboConfigBinding(prefix = "dubbo.applications.applicationBean", type = ApplicationConfig.class) + @EnableDubboConfigBinding(prefix = "dubbo.applications.applicationBean1", type = ApplicationConfig.class) }) @PropertySource("META-INF/config.properties") private static class TestConfig { diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java index ff21bcd0197..5a4222eb741 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java @@ -84,8 +84,8 @@ public void testMultiple() { context.refresh(); // application - ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); - Assert.assertEquals("dubbo-demo-application", applicationConfig.getName()); + ApplicationConfig applicationConfig = context.getBean("applicationBean1", ApplicationConfig.class); + Assert.assertEquals("dubbo-demo-application1", applicationConfig.getName()); ApplicationConfig applicationBean2 = context.getBean("applicationBean2", ApplicationConfig.class); Assert.assertEquals("dubbo-demo-application2", applicationBean2.getName()); diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java index f52f3af5fba..cb581190163 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java @@ -23,19 +23,17 @@ import com.alibaba.dubbo.config.ProtocolConfig; import com.alibaba.dubbo.config.ProviderConfig; import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.config.spring.util.ObjectUtils; import org.junit.Assert; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.PropertySource; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.MapPropertySource; -import org.springframework.core.env.StandardEnvironment; -import java.util.HashMap; -import java.util.Map; +import java.util.Set; +import java.util.TreeSet; -import static com.alibaba.dubbo.config.spring.context.annotation.DubboConfigConfigurationRegistrar.DUBBO_CONFIG_ORDER_PROPERTY_NAME; +import static java.util.Arrays.asList; /** * {@link EnableDubboConfig} Test @@ -44,26 +42,6 @@ */ public class EnableDubboConfigTest { - @Test - public void testOrder() { - Map source = new HashMap(); - source.put(DUBBO_CONFIG_ORDER_PROPERTY_NAME, "1"); - MapPropertySource propertySource = new MapPropertySource("test-property-source", source); - ConfigurableEnvironment environment = new StandardEnvironment(); - - environment.getPropertySources().addFirst(propertySource); - - DubboConfigConfigurationRegistrar selector = new DubboConfigConfigurationRegistrar(); - - selector.setEnvironment(environment); - - Assert.assertEquals(1, selector.getOrder()); - - selector.setOrder(2); - - Assert.assertEquals(2, selector.getOrder()); - } - @Test public void testSingle() { @@ -75,6 +53,8 @@ public void testSingle() { ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); Assert.assertEquals("dubbo-demo-application", applicationConfig.getName()); + Assert.assertArrayEquals(ObjectUtils.of("applicationBean"), context.getBeanNamesForType(ApplicationConfig.class)); + // module ModuleConfig moduleConfig = context.getBean("moduleBean", ModuleConfig.class); Assert.assertEquals("dubbo-demo-module", moduleConfig.getName()); @@ -110,10 +90,18 @@ public void testMultiple() { context.register(TestMultipleConfig.class); context.refresh(); + Set expectedBeanNames = new TreeSet(asList("applicationBean", "applicationBean1", "applicationBean2", "applicationBean3")); + Set actualBeanNames = new TreeSet(asList(context.getBeanNamesForType(ApplicationConfig.class))); + + Assert.assertEquals(expectedBeanNames, actualBeanNames); + // application ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); Assert.assertEquals("dubbo-demo-application", applicationConfig.getName()); + applicationConfig = context.getBean("applicationBean1", ApplicationConfig.class); + Assert.assertEquals("dubbo-demo-application1", applicationConfig.getName()); + ApplicationConfig applicationBean2 = context.getBean("applicationBean2", ApplicationConfig.class); Assert.assertEquals("dubbo-demo-application2", applicationBean2.getName()); @@ -122,13 +110,13 @@ public void testMultiple() { } - @EnableDubboConfig(multiple = true) + @EnableDubboConfig @PropertySource("META-INF/config.properties") private static class TestMultipleConfig { } - @EnableDubboConfig + @EnableDubboConfig(multiple = false) @PropertySource("META-INF/config.properties") private static class TestConfig { diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties index 6e728ccb208..d635aa97f93 100644 --- a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties @@ -27,6 +27,6 @@ dubbo.provider.host = 127.0.0.1 dubbo.consumer.client = netty # multiple Bean definition -dubbo.applications.applicationBean.name = dubbo-demo-application +dubbo.applications.applicationBean1.name = dubbo-demo-application1 dubbo.applications.applicationBean2.name = dubbo-demo-application2 dubbo.applications.applicationBean3.name = dubbo-demo-application3 \ No newline at end of file From 688bef39d017002992125998cece93cc005a2ff7 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Wed, 16 Jan 2019 14:27:38 +0800 Subject: [PATCH 25/38] Polish apache/incubator-dubbo#3192 : inline the source code of spring-context-support --- dependencies-bom/pom.xml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/dependencies-bom/pom.xml b/dependencies-bom/pom.xml index ca58f506cd2..2cf046a6bb3 100644 --- a/dependencies-bom/pom.xml +++ b/dependencies-bom/pom.xml @@ -103,8 +103,6 @@ 3.0.19.Final 8.5.31 - - 1.0.1 1.7.25 1.2 @@ -307,13 +305,6 @@ ${tomcat_embed_version} - - - com.alibaba.spring - spring-context-support - ${alibaba_spring_context_support_version} - - org.slf4j @@ -375,13 +366,6 @@ - - - com.alibaba.spring - spring-context-support - ${alibaba_spring_context_support_version} - - org.yaml From 85b0b54b449ce4e45641e8eff71a66478dffbde1 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 18 Jan 2019 09:27:38 +0800 Subject: [PATCH 26/38] Polish apache/incubator-dubbo#3189 Simplify externalized configuration of Dubbo Protocol name --- .../DubboConfigBindingBeanPostProcessor.java | 56 ++++++++++++-- .../DubboConfigBindingRegistrar.java | 10 ++- .../config/DubboConfigBeanCustomizer.java | 46 ++++++++++++ ...DefaultValueDubboConfigBeanCustomizer.java | 75 +++++++++++++++++++ ...bboConfigBindingBeanPostProcessorTest.java | 50 +++++++------ .../annotation/EnableDubboConfigTest.java | 11 ++- .../test/resources/META-INF/config.properties | 4 + 7 files changed, 221 insertions(+), 31 deletions(-) create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/DubboConfigBeanCustomizer.java create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/NamePropertyDefaultValueDubboConfigBeanCustomizer.java diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java index 46ace143af5..f87be246935 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java @@ -20,9 +20,9 @@ import com.alibaba.dubbo.config.AbstractConfig; import com.alibaba.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar; import com.alibaba.dubbo.config.spring.context.annotation.EnableDubboConfigBinding; +import com.alibaba.dubbo.config.spring.context.config.DubboConfigBeanCustomizer; import com.alibaba.dubbo.config.spring.context.properties.DefaultDubboConfigBinder; import com.alibaba.dubbo.config.spring.context.properties.DubboConfigBinder; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; @@ -30,8 +30,16 @@ import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.env.Environment; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors; + /** * Dubbo Config Binding {@link BeanPostProcessor} * @@ -62,6 +70,8 @@ public class DubboConfigBindingBeanPostProcessor implements BeanPostProcessor, A private boolean ignoreInvalidFields = true; + private List configBeanCustomizers = Collections.emptyList(); + /** * @param prefix the prefix of Configuration Properties * @param beanName the binding Bean Name @@ -80,18 +90,34 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro AbstractConfig dubboConfig = (AbstractConfig) bean; - dubboConfigBinder.bind(prefix, dubboConfig); + bind(prefix, dubboConfig); + + customize(beanName, dubboConfig); - if (log.isInfoEnabled()) { - log.info("The properties of bean [name : " + beanName + "] have been binding by prefix of " + - "configuration properties : " + prefix); - } } return bean; } + private void bind(String prefix, AbstractConfig dubboConfig) { + + dubboConfigBinder.bind(prefix, dubboConfig); + + if (log.isInfoEnabled()) { + log.info("The properties of bean [name : " + beanName + "] have been binding by prefix of " + + "configuration properties : " + prefix); + } + } + + private void customize(String beanName, AbstractConfig dubboConfig) { + + for (DubboConfigBeanCustomizer customizer : configBeanCustomizers) { + customizer.customize(beanName, dubboConfig); + } + + } + public boolean isIgnoreUnknownFields() { return ignoreUnknownFields; } @@ -129,6 +155,14 @@ public void setApplicationContext(ApplicationContext applicationContext) throws @Override public void afterPropertiesSet() throws Exception { + initDubboConfigBinder(); + + initConfigBeanCustomizers(); + + } + + private void initDubboConfigBinder() { + if (dubboConfigBinder == null) { try { dubboConfigBinder = applicationContext.getBean(DubboConfigBinder.class); @@ -146,6 +180,16 @@ public void afterPropertiesSet() throws Exception { } + private void initConfigBeanCustomizers() { + + Collection configBeanCustomizers = + beansOfTypeIncludingAncestors(applicationContext, DubboConfigBeanCustomizer.class).values(); + + this.configBeanCustomizers = new ArrayList(configBeanCustomizers); + + AnnotationAwareOrderComparator.sort(this.configBeanCustomizers); + } + /** * Create {@link DubboConfigBinder} instance. * diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java index 5e1c18ef81a..2f55f2965eb 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java @@ -18,7 +18,7 @@ import com.alibaba.dubbo.config.AbstractConfig; import com.alibaba.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor; - +import com.alibaba.dubbo.config.spring.context.config.NamePropertyDefaultValueDubboConfigBeanCustomizer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.config.BeanDefinition; @@ -41,6 +41,7 @@ import java.util.Map; import java.util.Set; +import static com.alibaba.dubbo.config.spring.util.BeanRegistrar.registerInfrastructureBean; import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties; import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.normalizePrefix; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; @@ -107,6 +108,8 @@ private void registerDubboConfigBeans(String prefix, } + registerDubboConfigBeanCustomizers(registry); + } private void registerDubboConfigBean(String beanName, Class configClass, @@ -149,6 +152,11 @@ private void registerDubboConfigBindingBeanPostProcessor(String prefix, String b } + private void registerDubboConfigBeanCustomizers(BeanDefinitionRegistry registry) { + registerInfrastructureBean(registry, "namePropertyDefaultValueDubboConfigBeanCustomizer", + NamePropertyDefaultValueDubboConfigBeanCustomizer.class); + } + @Override public void setEnvironment(Environment environment) { diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/DubboConfigBeanCustomizer.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/DubboConfigBeanCustomizer.java new file mode 100644 index 00000000000..42e1f6a2504 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/DubboConfigBeanCustomizer.java @@ -0,0 +1,46 @@ +/* + * 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.config; + +import com.alibaba.dubbo.config.AbstractConfig; +import com.alibaba.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor; +import com.alibaba.dubbo.config.spring.context.properties.DubboConfigBinder; +import org.springframework.context.ApplicationContext; +import org.springframework.core.Ordered; + +/** + * The Bean customizer for {@link AbstractConfig Dubbo Config}. Generally, The subclass will be registered as a Spring + * Bean that is used to {@link #customize(String, AbstractConfig) customize} {@link AbstractConfig Dubbo Config} bean + * after {@link DubboConfigBinder#bind(String, AbstractConfig) its binding}. + *

      + * If There are multiple {@link DubboConfigBeanCustomizer} beans in the Spring {@link ApplicationContext context}, they + * are executed orderly, thus the subclass should be aware to implement the {@link #getOrder()} method. + * + * @see DubboConfigBinder#bind(String, AbstractConfig) + * @see DubboConfigBindingBeanPostProcessor + * @since 2.6.6 + */ +public interface DubboConfigBeanCustomizer extends Ordered { + + /** + * Customize {@link AbstractConfig Dubbo Config Bean} + * + * @param beanName the name of {@link AbstractConfig Dubbo Config Bean} + * @param dubboConfigBean the instance of {@link AbstractConfig Dubbo Config Bean} + */ + void customize(String beanName, AbstractConfig dubboConfigBean); +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/NamePropertyDefaultValueDubboConfigBeanCustomizer.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/NamePropertyDefaultValueDubboConfigBeanCustomizer.java new file mode 100644 index 00000000000..d938218cf71 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/NamePropertyDefaultValueDubboConfigBeanCustomizer.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.context.config; + +import com.alibaba.dubbo.config.AbstractConfig; +import org.springframework.util.ReflectionUtils; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.Arrays; + +import static com.alibaba.dubbo.config.spring.util.ObjectUtils.of; +import static org.springframework.beans.BeanUtils.getPropertyDescriptor; + +/** + * {@link DubboConfigBeanCustomizer} for the default value for the "name" property that will be taken bean name + * if absent. + * + * @since 2.6.6 + */ +public class NamePropertyDefaultValueDubboConfigBeanCustomizer implements DubboConfigBeanCustomizer { + + /** + * The name of property that is "name" maybe is absent in target class + */ + private static final String PROPERTY_NAME = "name"; + + @Override + public void customize(String beanName, AbstractConfig dubboConfigBean) { + + PropertyDescriptor propertyDescriptor = getPropertyDescriptor(dubboConfigBean.getClass(), PROPERTY_NAME); + + if (propertyDescriptor != null) { // "name" property is present + + Method getNameMethod = propertyDescriptor.getReadMethod(); + + if (getNameMethod == null) { // if "getName" method is absent + return; + } + + Object propertyValue = ReflectionUtils.invokeMethod(getNameMethod, dubboConfigBean); + + if (propertyValue != null) { // If The return value of "getName" method is not null + return; + } + + Method setNameMethod = propertyDescriptor.getWriteMethod(); + if (setNameMethod != null && getNameMethod != null) { // "setName" and "getName" methods are present + if (Arrays.equals(of(String.class), setNameMethod.getParameterTypes())) { // the param type is String + // set bean name to the value of the "name" property + ReflectionUtils.invokeMethod(setNameMethod, dubboConfigBean, beanName); + } + } + } + } + + @Override + public int getOrder() { + return HIGHEST_PRECEDENCE; + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java index b98364b1cff..818eadecabe 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java @@ -17,51 +17,55 @@ package com.alibaba.dubbo.config.spring.beans.factory.annotation; import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.spring.context.config.NamePropertyDefaultValueDubboConfigBeanCustomizer; import com.alibaba.dubbo.config.spring.context.properties.DefaultDubboConfigBinder; -import com.alibaba.dubbo.config.spring.context.properties.DubboConfigBinder; - import org.junit.Assert; import org.junit.Test; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.PropertySource; - -import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; /** * {@link DubboConfigBindingBeanPostProcessor} */ -@PropertySource({"classpath:/META-INF/config.properties"}) -@Configuration +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = { + DefaultDubboConfigBinder.class, + NamePropertyDefaultValueDubboConfigBeanCustomizer.class, + DubboConfigBindingBeanPostProcessorTest.class +}) +@TestPropertySource(properties = { + "dubbo.application.id = dubbo-demo-application", + "dubbo.application.owner = mercyblitz", + "dubbo.application.organization = Apache", + +}) public class DubboConfigBindingBeanPostProcessorTest { - @Bean("applicationBean") + @Bean("dubbo-demo-application") public ApplicationConfig applicationConfig() { return new ApplicationConfig(); } @Bean - public DubboConfigBinder dubboConfigBinder() { - return new DefaultDubboConfigBinder(); + public DubboConfigBindingBeanPostProcessor bindingBeanPostProcessor() { + return new DubboConfigBindingBeanPostProcessor("dubbo.application", "dubbo-demo-application"); } + @Autowired + private ApplicationContext applicationContext; + @Test public void test() { - final AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); - - applicationContext.register(getClass()); - - Class processorClass = DubboConfigBindingBeanPostProcessor.class; - - applicationContext.registerBeanDefinition("DubboConfigBindingBeanPostProcessor", rootBeanDefinition(processorClass).addConstructorArgValue("dubbo.application").addConstructorArgValue("applicationBean").getBeanDefinition()); - - applicationContext.refresh(); - ApplicationConfig applicationConfig = applicationContext.getBean(ApplicationConfig.class); Assert.assertEquals("dubbo-demo-application", applicationConfig.getName()); - + Assert.assertEquals("mercyblitz", applicationConfig.getOwner()); + Assert.assertEquals("Apache", applicationConfig.getOrganization()); } } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java index cb581190163..15b462e4041 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java @@ -24,12 +24,12 @@ import com.alibaba.dubbo.config.ProviderConfig; import com.alibaba.dubbo.config.RegistryConfig; import com.alibaba.dubbo.config.spring.util.ObjectUtils; - import org.junit.Assert; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.PropertySource; +import java.util.Map; import java.util.Set; import java.util.TreeSet; @@ -108,6 +108,15 @@ public void testMultiple() { ApplicationConfig applicationBean3 = context.getBean("applicationBean3", ApplicationConfig.class); Assert.assertEquals("dubbo-demo-application3", applicationBean3.getName()); + + Map protocolConfigs = context.getBeansOfType(ProtocolConfig.class); + + for (Map.Entry entry : protocolConfigs.entrySet()) { + String beanName = entry.getKey(); + ProtocolConfig protocol = entry.getValue(); + Assert.assertEquals(beanName, protocol.getName()); + } + } @EnableDubboConfig diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties index d635aa97f93..1063fe68ff1 100644 --- a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties @@ -14,9 +14,13 @@ dubbo.module.name = dubbo-demo-module dubbo.registry.address = zookeeper://192.168.99.100:32770 ## protocol +dubbo.protocol.id = dubbo dubbo.protocol.name = dubbo dubbo.protocol.port = 20880 +dubbo.protocols.rest.port=8080 +dubbo.protocols.thrift.port=9090 + ## monitor dubbo.monitor.address = zookeeper://127.0.0.1:32770 From 1f74e5226eb40981679213c75d3742a8380b69e8 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Sat, 26 Jan 2019 15:21:15 +0800 Subject: [PATCH 27/38] Polish apache/incubator-dubbo#3193 --- .../dubbo/config/spring/context/annotation/EnableDubbo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubbo.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubbo.java index 25d8cad3e51..fff2fc4df2b 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubbo.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubbo.java @@ -76,6 +76,6 @@ * @see EnableDubboConfig#multiple() */ @AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple") - boolean multipleConfig() default false; + boolean multipleConfig() default true; } From 19ee8337c6dd802199c110421b8d3d93f17fd851 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Sat, 26 Jan 2019 15:35:34 +0800 Subject: [PATCH 28/38] Polish apache/incubator-dubbo#2987 --- .../factory/annotation/ServiceAnnotationBeanPostProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b39d23f7da9..0d1a0a9dd0f 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 @@ -262,7 +262,7 @@ private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, Bean registry.registerBeanDefinition(beanName, serviceBeanDefinition); if (logger.isInfoEnabled()) { - logger.warn("The BeanDefinition[" + serviceBeanDefinition + + logger.info("The BeanDefinition[" + serviceBeanDefinition + "] of ServiceBean has been registered with name : " + beanName); } From 8ff4f37704fac2541f8027cb63a33f72c0334893 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Mon, 28 Jan 2019 00:46:38 +0800 Subject: [PATCH 29/38] Polish apache/incubator-dubbo#3355 : Add the "protocol" attribute --- .../dubbo/config/annotation/Reference.java | 243 +++++++++--------- 1 file changed, 128 insertions(+), 115 deletions(-) diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/annotation/Reference.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/annotation/Reference.java index c043cb3bd3d..3220d9d23ad 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/annotation/Reference.java +++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/annotation/Reference.java @@ -1,115 +1,128 @@ -/* - * 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Reference - * - * @export - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE}) -public @interface Reference { - - Class interfaceClass() default void.class; - - String interfaceName() default ""; - - String version() default ""; - - String group() default ""; - - String url() default ""; - - String client() default ""; - - boolean generic() default false; - - boolean injvm() default false; - - boolean check() default true; - - boolean init() default false; - - boolean lazy() default false; - - boolean stubevent() default false; - - String reconnect() default ""; - - boolean sticky() default false; - - String proxy() default ""; - - String stub() default ""; - - String cluster() default ""; - - int connections() default 0; - - int callbacks() default 0; - - String onconnect() default ""; - - String ondisconnect() default ""; - - String owner() default ""; - - String layer() default ""; - - int retries() default 2; - - String loadbalance() default ""; - - boolean async() default false; - - int actives() default 0; - - boolean sent() default false; - - String mock() default ""; - - String validation() default ""; - - int timeout() default 0; - - String cache() default ""; - - String[] filter() default {}; - - String[] listener() default {}; - - String[] parameters() default {}; - - String application() default ""; - - String module() default ""; - - String consumer() default ""; - - String monitor() default ""; - - String[] registry() default {}; - -} +/* + * 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.annotation; + +import com.alibaba.dubbo.common.Constants; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import static com.alibaba.dubbo.common.Constants.DEFAULT_PROTOCOL; + +/** + * Reference + * + * @export + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE}) +public @interface Reference { + + Class interfaceClass() default void.class; + + String interfaceName() default ""; + + String version() default ""; + + String group() default ""; + + String url() default ""; + + String client() default ""; + + boolean generic() default false; + + boolean injvm() default false; + + boolean check() default true; + + boolean init() default false; + + boolean lazy() default false; + + boolean stubevent() default false; + + String reconnect() default ""; + + boolean sticky() default false; + + String proxy() default ""; + + String stub() default ""; + + String cluster() default ""; + + int connections() default 0; + + int callbacks() default 0; + + String onconnect() default ""; + + String ondisconnect() default ""; + + String owner() default ""; + + String layer() default ""; + + int retries() default 2; + + String loadbalance() default ""; + + boolean async() default false; + + int actives() default 0; + + boolean sent() default false; + + String mock() default ""; + + String validation() default ""; + + int timeout() default 0; + + String cache() default ""; + + String[] filter() default {}; + + String[] listener() default {}; + + String[] parameters() default {}; + + String application() default ""; + + String module() default ""; + + String consumer() default ""; + + String monitor() default ""; + + String[] registry() default {}; + + /** + * The communication protocol of Dubbo Service + * + * @return the default value is "dubbo" + * @see Constants#DEFAULT_PROTOCOL + * @since 2.6.6 + */ + String protocol() default DEFAULT_PROTOCOL; + +} From ebeb1dd8ae2379fa38aa0acc53060446bbe89b86 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Mon, 28 Jan 2019 00:46:58 +0800 Subject: [PATCH 30/38] Polish apache/incubator-dubbo#3355 : Still exists the issues in service discovery. --- dubbo-config/dubbo-config-spring/pom.xml | 86 ++++++ .../annotation/AnnotationBeanNameBuilder.java | 142 ++++++++++ .../ReferenceAnnotationBeanPostProcessor.java | 6 +- .../ServiceAnnotationBeanPostProcessor.java | 4 +- .../annotation/ServiceBeanNameBuilder.java | 2 + .../AnnotationBeanNameBuilderTest.java | 83 ++++++ ...erenceAnnotationBeanPostProcessorTest.java | 2 +- .../ServiceBeanNameBuilderTest.java | 1 + .../multiple/EmbeddedZooKeeper.java | 252 ++++++++++++++++++ .../MultipleProtocolsServiceConsumer.java | 62 +++++ .../provider/DefaultHelloService.java | 36 +++ .../MultipleProtocolsServiceProvider.java | 51 ++++ .../META-INF/dubbo-common.properties | 2 + .../multiple-protocols-consumer.properties | 1 + .../multiple-protocols-provider.properties | 6 + 15 files changed, 731 insertions(+), 5 deletions(-) create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilder.java create mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilderTest.java create mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/EmbeddedZooKeeper.java create mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/consumer/MultipleProtocolsServiceConsumer.java create mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/DefaultHelloService.java create mode 100644 dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/MultipleProtocolsServiceProvider.java create mode 100644 dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-common.properties create mode 100644 dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-consumer.properties create mode 100644 dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-provider.properties diff --git a/dubbo-config/dubbo-config-spring/pom.xml b/dubbo-config/dubbo-config-spring/pom.xml index b73627870a1..a239a53d154 100644 --- a/dubbo-config/dubbo-config-spring/pom.xml +++ b/dubbo-config/dubbo-config-spring/pom.xml @@ -52,83 +52,169 @@ javax.servlet-api provided + + + + + io.netty + netty-all + test + + + + + org.jboss.resteasy + resteasy-jaxrs + test + + + + org.jboss.resteasy + resteasy-client + test + + + + org.jboss.resteasy + resteasy-netty4 + test + + + + javax.validation + validation-api + test + + + + org.jboss.resteasy + resteasy-jackson-provider + test + + + + org.jboss.resteasy + resteasy-jaxb-provider + test + + com.alibaba dubbo-registry-default ${project.parent.version} test + + + com.alibaba + dubbo-registry-zookeeper + ${project.parent.version} + test + + com.alibaba dubbo-monitor-default ${project.parent.version} test + com.alibaba dubbo-rpc-dubbo ${project.parent.version} test + + + com.alibaba + dubbo-rpc-rest + ${project.parent.version} + test + + com.alibaba dubbo-rpc-rmi ${project.parent.version} test + com.alibaba dubbo-rpc-injvm ${project.parent.version} + com.alibaba dubbo-remoting-netty ${project.parent.version} test + com.alibaba dubbo-serialization-hessian2 ${project.parent.version} test + javax.validation validation-api test + org.hibernate hibernate-validator test + org.glassfish javax.el test + org.springframework spring-tx test + org.springframework spring-test test + org.apache.tomcat.embed tomcat-embed-core test + org.yaml snakeyaml test + + + org.apache.zookeeper + zookeeper + test + + + + org.apache.curator + curator-framework + test + + diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilder.java new file mode 100644 index 00000000000..cf72a4a1b93 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilder.java @@ -0,0 +1,142 @@ +/* + * 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.common.Constants; +import com.alibaba.dubbo.config.annotation.Reference; +import com.alibaba.dubbo.config.annotation.Service; +import com.alibaba.dubbo.registry.Registry; + +import org.springframework.core.env.Environment; + +import static com.alibaba.dubbo.common.Constants.CONSUMERS_CATEGORY; +import static com.alibaba.dubbo.common.Constants.DEFAULT_PROTOCOL; +import static com.alibaba.dubbo.common.Constants.PROVIDERS_CATEGORY; +import static com.alibaba.dubbo.config.spring.util.AnnotationUtils.resolveInterfaceName; +import static org.springframework.util.StringUtils.arrayToCommaDelimitedString; +import static org.springframework.util.StringUtils.hasText; + +/** + * The Bean Name Builder for the annotations {@link Service} and {@link Reference} + *

      + * The naming rule is consistent with the the implementation {@link Registry} that is based on the service-name aware + * infrastructure, e.g Spring Cloud, Cloud Native and so on. + *

      + * The pattern of bean name : ${category}:${protocol}:${serviceInterface}:${version}:${group}. + *

      + * ${version} and ${group} are optional. + * + * @since 2.6.6 + */ +class AnnotationBeanNameBuilder { + + private static final String SEPARATOR = ":"; + + // Required properties + + private final String category; + + private final String protocol; + + private final String interfaceClassName; + + // Optional properties + + private String version; + + private String group; + + private Environment environment; + + private AnnotationBeanNameBuilder(String category, String protocol, String interfaceClassName) { + this.category = category; + this.protocol = protocol; + this.interfaceClassName = interfaceClassName; + } + + private AnnotationBeanNameBuilder(Service service, Class interfaceClass) { + this(PROVIDERS_CATEGORY, resolveProtocol(service.protocol()), resolveInterfaceName(service, interfaceClass)); + this.group(service.group()); + this.version(service.version()); + } + + private AnnotationBeanNameBuilder(Reference reference, Class interfaceClass) { + this(CONSUMERS_CATEGORY, resolveProtocol(reference.protocol()), resolveInterfaceName(reference, interfaceClass)); + this.group(reference.group()); + this.version(reference.version()); + } + + public static AnnotationBeanNameBuilder create(Service service, Class interfaceClass) { + return new AnnotationBeanNameBuilder(service, interfaceClass); + } + + public static AnnotationBeanNameBuilder create(Reference reference, Class interfaceClass) { + return new AnnotationBeanNameBuilder(reference, interfaceClass); + } + + private static void append(StringBuilder builder, String value) { + if (hasText(value)) { + builder.append(SEPARATOR).append(value); + } + } + + public AnnotationBeanNameBuilder group(String group) { + this.group = group; + return this; + } + + public AnnotationBeanNameBuilder version(String version) { + this.version = version; + return this; + } + + public AnnotationBeanNameBuilder environment(Environment environment) { + this.environment = environment; + return this; + } + + /** + * Resolve the protocol + * + * @param protocols one or more protocols + * @return if protocols == null, it will return + * {@link Constants#DEFAULT_PROTOCOL "dubbo"} as the default protocol + * @see Constants#DEFAULT_PROTOCOL + */ + private static String resolveProtocol(String... protocols) { + String protocol = arrayToCommaDelimitedString(protocols); + return hasText(protocol) ? protocol : DEFAULT_PROTOCOL; + } + + /** + * Build bean name while resolve the placeholders if possible. + * + * @return pattern : ${category}:${protocol}:${serviceInterface}:${version}:${group} + */ + public String build() { + // Append the required properties + StringBuilder beanNameBuilder = new StringBuilder(category); + append(beanNameBuilder, protocol); + append(beanNameBuilder, interfaceClassName); + // Append the optional properties + append(beanNameBuilder, version); + append(beanNameBuilder, group); + String beanName = beanNameBuilder.toString(); + // Resolve placeholders + return environment != null ? environment.resolvePlaceholders(beanName) : beanName; + } +} 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 54c981e8103..467810de0b2 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 @@ -169,14 +169,16 @@ protected String buildInjectedObjectCacheKey(Reference reference, Object bean, S String key = buildReferencedBeanName(reference, injectedType) + "#source=" + (injectedElement.getMember()) + - "#attributes=" + AnnotationUtils.getAttributes(reference,getEnvironment(),true); + "#attributes=" + AnnotationUtils.getAttributes(reference, getEnvironment(), true); return key; } private String buildReferencedBeanName(Reference reference, Class injectedType) { - ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, injectedType, getEnvironment()); + AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(reference, injectedType); + + builder.environment(getEnvironment()); return getEnvironment().resolvePlaceholders(builder.build()); } 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 0d1a0a9dd0f..677710048fe 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 @@ -289,11 +289,11 @@ private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, Bean */ private String generateServiceBeanName(Service service, Class interfaceClass, String annotatedServiceBeanName) { - ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, interfaceClass, environment); + AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(service, interfaceClass); + builder.environment(environment); return builder.build(); - } private Class resolveServiceInterfaceClass(Class annotatedServiceBeanClass, Service service) { 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 index 06b2dfa8f0e..4a97a24b6d7 100644 --- 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 @@ -35,7 +35,9 @@ * @see ServiceBean * @see ReferenceBean * @since 2.6.5 + * @deprecated {@link AnnotationBeanNameBuilder} as the replacement */ +@Deprecated class ServiceBeanNameBuilder { private static final String SEPARATOR = ":"; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilderTest.java new file mode 100644 index 00000000000..28c53ccd06a --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilderTest.java @@ -0,0 +1,83 @@ +/* + * 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.Before; +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.AnnotationBeanNameBuilderTest.GROUP; +import static com.alibaba.dubbo.config.spring.beans.factory.annotation.AnnotationBeanNameBuilderTest.VERSION; + +/** + * {@link AnnotationBeanNameBuilder} Test + * + * @see AnnotationBeanNameBuilder + * @since 2.6.6 + */ +@Service(interfaceClass = DemoService.class, group = GROUP, version = VERSION, + application = "application", module = "module", registry = {"1", "2", "3"}) +public class AnnotationBeanNameBuilderTest { + + @Reference(interfaceClass = DemoService.class, group = "DUBBO", version = "${dubbo.version}", + 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"; + + private MockEnvironment environment; + + @Before + public void prepare() { + environment = new MockEnvironment(); + environment.setProperty("dubbo.version", "1.0.0"); + } + + @Test + public void testServiceAnnotation() { + Service service = AnnotationUtils.getAnnotation(AnnotationBeanNameBuilderTest.class, Service.class); + AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(service, INTERFACE_CLASS); + Assert.assertEquals("providers:dubbo:com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO", + builder.build()); + + builder.environment(environment); + Assert.assertEquals("providers:dubbo:com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO", + builder.build()); + } + + @Test + public void testReferenceAnnotation() { + Reference reference = AnnotationUtils.getAnnotation(ReflectionUtils.findField(AnnotationBeanNameBuilderTest.class, "INTERFACE_CLASS"), Reference.class); + AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(reference, INTERFACE_CLASS); + Assert.assertEquals("consumers:dubbo:com.alibaba.dubbo.config.spring.api.DemoService:${dubbo.version}:DUBBO", + builder.build()); + + builder.environment(environment); + Assert.assertEquals("consumers:dubbo:com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO", + builder.build()); + } + +} 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 0003d699211..dcb4127cf53 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 @@ -229,7 +229,7 @@ public DemoService getDemoService() { return demoService; } - @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345") + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", protocol = "dubbo") 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/ServiceBeanNameBuilderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java index 84451bcaf4a..91b4b7043aa 100644 --- 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 @@ -37,6 +37,7 @@ */ @Service(interfaceClass = DemoService.class, group = GROUP, version = VERSION, application = "application", module = "module", registry = {"1", "2", "3"}) +@Deprecated public class ServiceBeanNameBuilderTest { @Reference(interfaceClass = DemoService.class, group = "DUBBO", version = "1.0.0", diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/EmbeddedZooKeeper.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/EmbeddedZooKeeper.java new file mode 100644 index 00000000000..05c08e72e17 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/EmbeddedZooKeeper.java @@ -0,0 +1,252 @@ +/* + * 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.multiple; + + +import org.apache.zookeeper.server.ServerConfig; +import org.apache.zookeeper.server.ZooKeeperServerMain; +import org.apache.zookeeper.server.quorum.QuorumPeerConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.SmartLifecycle; +import org.springframework.util.ErrorHandler; +import org.springframework.util.SocketUtils; + +import java.io.File; +import java.lang.reflect.Method; +import java.util.Properties; +import java.util.UUID; + +/** + * from: https://github.com/spring-projects/spring-xd/blob/v1.3.1.RELEASE/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/zookeeper/ZooKeeperUtils.java + *

      + * Helper class to start an embedded instance of standalone (non clustered) ZooKeeper. + *

      + * NOTE: at least an external standalone server (if not an ensemble) are recommended, even for + * org.springframework.xd.dirt.server.singlenode.SingleNodeApplication + * + * @author Patrick Peralta + * @author Mark Fisher + * @author David Turanski + */ +public class EmbeddedZooKeeper implements SmartLifecycle { + + /** + * Logger. + */ + private static final Logger logger = LoggerFactory.getLogger(EmbeddedZooKeeper.class); + + /** + * ZooKeeper client port. This will be determined dynamically upon startup. + */ + private final int clientPort; + + /** + * Whether to auto-start. Default is true. + */ + private boolean autoStartup = true; + + /** + * Lifecycle phase. Default is 0. + */ + private int phase = 0; + + /** + * Thread for running the ZooKeeper server. + */ + private volatile Thread zkServerThread; + + /** + * ZooKeeper server. + */ + private volatile ZooKeeperServerMain zkServer; + + /** + * {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread. + */ + private ErrorHandler errorHandler; + + private boolean daemon = true; + + /** + * Construct an EmbeddedZooKeeper with a random port. + */ + public EmbeddedZooKeeper() { + clientPort = SocketUtils.findAvailableTcpPort(); + } + + /** + * Construct an EmbeddedZooKeeper with the provided port. + * + * @param clientPort port for ZooKeeper server to bind to + */ + public EmbeddedZooKeeper(int clientPort, boolean daemon) { + this.clientPort = clientPort; + this.daemon = daemon; + } + + /** + * Returns the port that clients should use to connect to this embedded server. + * + * @return dynamically determined client port + */ + public int getClientPort() { + return this.clientPort; + } + + /** + * Specify whether to start automatically. Default is true. + * + * @param autoStartup whether to start automatically + */ + public void setAutoStartup(boolean autoStartup) { + this.autoStartup = autoStartup; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isAutoStartup() { + return this.autoStartup; + } + + /** + * Specify the lifecycle phase for the embedded server. + * + * @param phase the lifecycle phase + */ + public void setPhase(int phase) { + this.phase = phase; + } + + /** + * {@inheritDoc} + */ + @Override + public int getPhase() { + return this.phase; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isRunning() { + return (zkServerThread != null); + } + + /** + * Start the ZooKeeper server in a background thread. + *

      + * Register an error handler via {@link #setErrorHandler} in order to handle + * any exceptions thrown during startup or execution. + */ + @Override + public synchronized void start() { + if (zkServerThread == null) { + zkServerThread = new Thread(new ServerRunnable(), "ZooKeeper Server Starter"); + zkServerThread.setDaemon(daemon); + zkServerThread.start(); + } + } + + /** + * Shutdown the ZooKeeper server. + */ + @Override + public synchronized void stop() { + if (zkServerThread != null) { + // The shutdown method is protected...thus this hack to invoke it. + // This will log an exception on shutdown; see + // https://issues.apache.org/jira/browse/ZOOKEEPER-1873 for details. + try { + Method shutdown = ZooKeeperServerMain.class.getDeclaredMethod("shutdown"); + shutdown.setAccessible(true); + shutdown.invoke(zkServer); + } catch (Exception e) { + throw new RuntimeException(e); + } + + // It is expected that the thread will exit after + // the server is shutdown; this will block until + // the shutdown is complete. + try { + zkServerThread.join(5000); + zkServerThread = null; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + logger.warn("Interrupted while waiting for embedded ZooKeeper to exit"); + // abandoning zk thread + zkServerThread = null; + } + } + } + + /** + * Stop the server if running and invoke the callback when complete. + */ + @Override + public void stop(Runnable callback) { + stop(); + callback.run(); + } + + /** + * Provide an {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread. If none + * is provided, only error-level logging will occur. + * + * @param errorHandler the {@link ErrorHandler} to be invoked + */ + public void setErrorHandler(ErrorHandler errorHandler) { + this.errorHandler = errorHandler; + } + + /** + * Runnable implementation that starts the ZooKeeper server. + */ + private class ServerRunnable implements Runnable { + + @Override + public void run() { + try { + Properties properties = new Properties(); + File file = new File(System.getProperty("java.io.tmpdir") + + File.separator + UUID.randomUUID()); + file.deleteOnExit(); + properties.setProperty("dataDir", file.getAbsolutePath()); + properties.setProperty("clientPort", String.valueOf(clientPort)); + + QuorumPeerConfig quorumPeerConfig = new QuorumPeerConfig(); + quorumPeerConfig.parseProperties(properties); + + zkServer = new ZooKeeperServerMain(); + ServerConfig configuration = new ServerConfig(); + configuration.readFrom(quorumPeerConfig); + + zkServer.runFromConfig(configuration); + } catch (Exception e) { + if (errorHandler != null) { + errorHandler.handleError(e); + } else { + logger.error("Exception running embedded ZooKeeper", e); + } + } + } + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/consumer/MultipleProtocolsServiceConsumer.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/consumer/MultipleProtocolsServiceConsumer.java new file mode 100644 index 00000000000..2eeb073b49c --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/consumer/MultipleProtocolsServiceConsumer.java @@ -0,0 +1,62 @@ +/* + * 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.multiple.consumer; + +import com.alibaba.dubbo.config.annotation.Reference; +import com.alibaba.dubbo.config.spring.api.HelloService; +import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +/** + * Multiple Protocols Test + */ + +public class MultipleProtocolsServiceConsumer { + + @EnableDubbo + @PropertySource({ + "classpath:/META-INF/multiple-protocols-consumer.properties", + "classpath:/META-INF/dubbo-common.properties" + }) + @Configuration + static class ConsumerConfiguration { + + @Reference(version = "${hello.service.version}", protocol = "dubbo") + private HelloService dubboHelloService; + +// @Reference(version = "${hello.service.version}", protocol = "rest") +// private HelloService restHelloService; + + } + + public static void main(String[] args) { + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(ConsumerConfiguration.class); + context.refresh(); + + ConsumerConfiguration configuration = context.getBean(ConsumerConfiguration.class); + System.out.println(configuration.dubboHelloService.sayHello("mercyblitz")); +// System.out.println(configuration.restHelloService.sayHello("mercyblitz")); + + context.close(); + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/DefaultHelloService.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/DefaultHelloService.java new file mode 100644 index 00000000000..60c1dea0201 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/DefaultHelloService.java @@ -0,0 +1,36 @@ +/* + * 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.multiple.provider; + +import com.alibaba.dubbo.config.annotation.Service; +import com.alibaba.dubbo.config.spring.api.HelloService; +import com.alibaba.dubbo.rpc.RpcContext; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; + +@Service(version = "${hello.service.version}", protocol = {"dubbo"}) +@Path("/hello-service") +public class DefaultHelloService implements HelloService { + + @Override + @GET + public String sayHello(@QueryParam("name") String name) { + return String.format("[%s] Hello , %s", RpcContext.getContext().getUrl(), name); + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/MultipleProtocolsServiceProvider.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/MultipleProtocolsServiceProvider.java new file mode 100644 index 00000000000..8e3981a499f --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/MultipleProtocolsServiceProvider.java @@ -0,0 +1,51 @@ +/* + * 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.multiple.provider; + +import com.alibaba.dubbo.config.spring.beans.factory.annotation.multiple.EmbeddedZooKeeper; +import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.PropertySource; + +import java.io.IOException; + +/** + * Multiple Protocols Service Provider + */ +@EnableDubbo +@PropertySource({ + "classpath:/META-INF/multiple-protocols-provider.properties", + "classpath:/META-INF/dubbo-common.properties" +}) +public class MultipleProtocolsServiceProvider { + + public static void main(String[] args) throws IOException { + EmbeddedZooKeeper embeddedZooKeeper = new EmbeddedZooKeeper(2181, false); + embeddedZooKeeper.start(); + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(MultipleProtocolsServiceProvider.class); + context.refresh(); + + System.out.println("Enter any key to close the application"); + System.in.read(); + + context.close(); + embeddedZooKeeper.stop(); + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-common.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-common.properties new file mode 100644 index 00000000000..36146a165b7 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-common.properties @@ -0,0 +1,2 @@ +dubbo.registry.address=zookeeper://127.0.0.1:2181 +hello.service.version=1.0.0 \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-consumer.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-consumer.properties new file mode 100644 index 00000000000..abbe51ce929 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-consumer.properties @@ -0,0 +1 @@ +dubbo.application.id=provider \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-provider.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-provider.properties new file mode 100644 index 00000000000..98790494336 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-provider.properties @@ -0,0 +1,6 @@ +dubbo.application.id=provider +dubbo.protocols.dubbo.name=dubbo +dubbo.protocols.dubbo.port=12345 +dubbo.protocols.rest.name=rest +dubbo.protocols.rest.port=9090 +dubbo.protocols.rest.server=netty \ No newline at end of file From 5026c70b2b2c8ed96b888135158f6a777b50b19b Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Tue, 29 Jan 2019 17:40:29 +0800 Subject: [PATCH 31/38] Polish apache/incubator-dubbo#3355 : fix the issues in samples --- .../dubbo/config/annotation/Reference.java | 9 ++---- .../annotation/ReferenceBeanBuilder.java | 17 ++++++++++ .../dubbo/config/spring/api/HelloService.java | 9 +++++- .../MultipleProtocolsServiceConsumer.java | 21 ++++++++++-- .../provider/DefaultHelloService.java | 10 ++---- .../MultipleProtocolsServiceProvider.java | 7 ++-- .../META-INF/spring/dubbo-rest-consumer.xml | 32 +++++++++++++++++++ 7 files changed, 82 insertions(+), 23 deletions(-) create mode 100644 dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-rest-consumer.xml diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/annotation/Reference.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/annotation/Reference.java index 3220d9d23ad..b3a93d7b72d 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/annotation/Reference.java +++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/annotation/Reference.java @@ -16,16 +16,12 @@ */ package com.alibaba.dubbo.config.annotation; -import com.alibaba.dubbo.common.Constants; - import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import static com.alibaba.dubbo.common.Constants.DEFAULT_PROTOCOL; - /** * Reference * @@ -119,10 +115,9 @@ /** * The communication protocol of Dubbo Service * - * @return the default value is "dubbo" - * @see Constants#DEFAULT_PROTOCOL + * @return the default value is "" * @since 2.6.6 */ - String protocol() default DEFAULT_PROTOCOL; + String protocol() default ""; } 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 9b92d214169..27de58bf71e 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 @@ -31,6 +31,7 @@ import java.beans.PropertyEditorSupport; import java.util.Map; +import static com.alibaba.dubbo.common.Constants.DEFAULT_PROTOCOL; 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; @@ -122,6 +123,22 @@ public void setAsText(String text) throws java.lang.IllegalArgumentException { // Bind annotation attributes dataBinder.bind(new AnnotationPropertyValuesAdapter(reference, applicationContext.getEnvironment(), IGNORE_FIELD_NAMES)); + setProtocolIfAbsent(reference, referenceBean); + } + + /** + * If ReferenceBean.protocol is empty and @Reference.protocol() is the default value, + * ReferenceBean.protocol is about to set the default protocol forcibly. + * + * @param reference {@link Reference} annotation + * @param referenceBean {@link ReferenceBean} Object + * @since 2.6.6 + */ + private void setProtocolIfAbsent(Reference reference, ReferenceBean referenceBean) { + if (!StringUtils.hasText(referenceBean.getProtocol()) + && DEFAULT_PROTOCOL.equals(reference.protocol())) { + referenceBean.setProtocol(DEFAULT_PROTOCOL); + } } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java index 1feb2bd5223..367ad9e37c8 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java @@ -17,6 +17,13 @@ package com.alibaba.dubbo.config.spring.api; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; + +@Path("/hello-service") public interface HelloService { - String sayHello(String name); + + @GET + String sayHello(@QueryParam("name") String name); } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/consumer/MultipleProtocolsServiceConsumer.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/consumer/MultipleProtocolsServiceConsumer.java index 2eeb073b49c..5166db8f6f1 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/consumer/MultipleProtocolsServiceConsumer.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/consumer/MultipleProtocolsServiceConsumer.java @@ -41,11 +41,26 @@ static class ConsumerConfiguration { @Reference(version = "${hello.service.version}", protocol = "dubbo") private HelloService dubboHelloService; -// @Reference(version = "${hello.service.version}", protocol = "rest") -// private HelloService restHelloService; + @Reference(version = "${hello.service.version}", protocol = "rest") + private HelloService restHelloService; + +// @Bean +// public ReferenceBean restReferenceBean(@Value("${hello.service.version}") String version) { +// ReferenceBean referenceBean = new ReferenceBean(); +// referenceBean.setVersion(version); +// referenceBean.setProtocol("rest"); +// referenceBean.setInterface(HelloService.class); +// return referenceBean; +// } } +// @ImportResource("classpath:/META-INF/spring/dubbo-rest-consumer.xml") +// @Configuration +// static class ConsumerXMLConfiguration { +// } + + public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); @@ -54,7 +69,7 @@ public static void main(String[] args) { ConsumerConfiguration configuration = context.getBean(ConsumerConfiguration.class); System.out.println(configuration.dubboHelloService.sayHello("mercyblitz")); -// System.out.println(configuration.restHelloService.sayHello("mercyblitz")); + System.out.println(configuration.restHelloService.sayHello("mercyblitz")); context.close(); } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/DefaultHelloService.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/DefaultHelloService.java index 60c1dea0201..43a7ced1cfe 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/DefaultHelloService.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/DefaultHelloService.java @@ -20,17 +20,11 @@ import com.alibaba.dubbo.config.spring.api.HelloService; import com.alibaba.dubbo.rpc.RpcContext; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.QueryParam; - -@Service(version = "${hello.service.version}", protocol = {"dubbo"}) -@Path("/hello-service") +@Service(version = "${hello.service.version}", protocol = {"dubbo", "rest"}) public class DefaultHelloService implements HelloService { @Override - @GET - public String sayHello(@QueryParam("name") String name) { + public String sayHello(String name) { return String.format("[%s] Hello , %s", RpcContext.getContext().getUrl(), name); } } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/MultipleProtocolsServiceProvider.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/MultipleProtocolsServiceProvider.java index 8e3981a499f..e55d70acea2 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/MultipleProtocolsServiceProvider.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/MultipleProtocolsServiceProvider.java @@ -16,7 +16,6 @@ */ package com.alibaba.dubbo.config.spring.beans.factory.annotation.multiple.provider; -import com.alibaba.dubbo.config.spring.beans.factory.annotation.multiple.EmbeddedZooKeeper; import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -35,8 +34,8 @@ public class MultipleProtocolsServiceProvider { public static void main(String[] args) throws IOException { - EmbeddedZooKeeper embeddedZooKeeper = new EmbeddedZooKeeper(2181, false); - embeddedZooKeeper.start(); +// EmbeddedZooKeeper embeddedZooKeeper = new EmbeddedZooKeeper(2181, false); +// embeddedZooKeeper.start(); AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(MultipleProtocolsServiceProvider.class); @@ -46,6 +45,6 @@ public static void main(String[] args) throws IOException { System.in.read(); context.close(); - embeddedZooKeeper.stop(); +// embeddedZooKeeper.stop(); } } diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-rest-consumer.xml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-rest-consumer.xml new file mode 100644 index 00000000000..c7db5ff57e6 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-rest-consumer.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + \ No newline at end of file From 4ad9aeb947fa5fd2b510d07481cf37498b1977a6 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Wed, 30 Jan 2019 16:24:23 +0800 Subject: [PATCH 32/38] Polish apache/incubator-dubbo#3355 : fix the issues in samples --- .../annotation/ReferenceBeanBuilder.java | 17 ----------------- 1 file changed, 17 deletions(-) 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 27de58bf71e..9b92d214169 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 @@ -31,7 +31,6 @@ import java.beans.PropertyEditorSupport; import java.util.Map; -import static com.alibaba.dubbo.common.Constants.DEFAULT_PROTOCOL; 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; @@ -123,22 +122,6 @@ public void setAsText(String text) throws java.lang.IllegalArgumentException { // Bind annotation attributes dataBinder.bind(new AnnotationPropertyValuesAdapter(reference, applicationContext.getEnvironment(), IGNORE_FIELD_NAMES)); - setProtocolIfAbsent(reference, referenceBean); - } - - /** - * If ReferenceBean.protocol is empty and @Reference.protocol() is the default value, - * ReferenceBean.protocol is about to set the default protocol forcibly. - * - * @param reference {@link Reference} annotation - * @param referenceBean {@link ReferenceBean} Object - * @since 2.6.6 - */ - private void setProtocolIfAbsent(Reference reference, ReferenceBean referenceBean) { - if (!StringUtils.hasText(referenceBean.getProtocol()) - && DEFAULT_PROTOCOL.equals(reference.protocol())) { - referenceBean.setProtocol(DEFAULT_PROTOCOL); - } } From dc0bf446e54072d3781e745832f33e6628df2149 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Wed, 30 Jan 2019 16:36:21 +0800 Subject: [PATCH 33/38] Polish apache/incubator-dubbo#3296 : Merge and enhancement dubbo-registry-nacos --- .../registry/support/DubboRegistration.java | 93 ++++ .../dubbo/registry/support/Registration.java | 53 ++ .../support/ServiceInstanceRegistry.java | 475 ++++++++++++++++++ dubbo-registry/dubbo-registry-nacos/pom.xml | 144 ++++++ .../dubbo/registry/nacos/NacosRegistry.java | 198 ++++++++ .../registry/nacos/NacosRegistryFactory.java | 108 ++++ ...com.alibaba.dubbo.registry.RegistryFactory | 1 + .../DemoServiceConsumerBootstrap.java | 59 +++ .../DemoServiceConsumerXmlBootstrap.java | 42 ++ .../DemoServiceProviderBootstrap.java | 41 ++ .../DemoServiceProviderXmlBootstrap.java | 37 ++ .../dubbo/demo/service/DefaultService.java | 46 ++ .../dubbo/demo/service/DemoService.java | 34 ++ .../nacos/NacosRegistryFactoryTest.java | 25 + .../registry/nacos/NacosRegistryTest.java | 32 ++ .../spring/dubbo-consumer-context.xml | 16 + .../spring/dubbo-provider-context.xml | 21 + .../test/resources/consumer-config.properties | 6 + .../test/resources/provider-config.properties | 14 + dubbo-registry/pom.xml | 1 + 20 files changed, 1446 insertions(+) create mode 100644 dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/DubboRegistration.java create mode 100644 dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/Registration.java create mode 100644 dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/ServiceInstanceRegistry.java create mode 100644 dubbo-registry/dubbo-registry-nacos/pom.xml create mode 100644 dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistry.java create mode 100644 dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactory.java create mode 100644 dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory create mode 100644 dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java create mode 100644 dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java create mode 100644 dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderBootstrap.java create mode 100644 dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderXmlBootstrap.java create mode 100644 dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DefaultService.java create mode 100644 dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DemoService.java create mode 100644 dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactoryTest.java create mode 100644 dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryTest.java create mode 100644 dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-consumer-context.xml create mode 100644 dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-provider-context.xml create mode 100644 dubbo-registry/dubbo-registry-nacos/src/test/resources/consumer-config.properties create mode 100644 dubbo-registry/dubbo-registry-nacos/src/test/resources/provider-config.properties diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/DubboRegistration.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/DubboRegistration.java new file mode 100644 index 00000000000..50deb0ab026 --- /dev/null +++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/DubboRegistration.java @@ -0,0 +1,93 @@ +/* + * 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.registry.support; + +import java.util.Map; + +/** + * Dubbo Registration + * + * @since 2.6.6 + */ +class DubboRegistration implements Registration { + + private String serviceName; + + private String ip; + + private int port; + + private Map metadata; + + @Override + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + @Override + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + @Override + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + @Override + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DubboRegistration that = (DubboRegistration) o; + + if (port != that.port) return false; + if (serviceName != null ? !serviceName.equals(that.serviceName) : that.serviceName != null) return false; + if (ip != null ? !ip.equals(that.ip) : that.ip != null) return false; + return metadata != null ? metadata.equals(that.metadata) : that.metadata == null; + } + + @Override + public int hashCode() { + int result = serviceName != null ? serviceName.hashCode() : 0; + result = 31 * result + (ip != null ? ip.hashCode() : 0); + result = 31 * result + port; + result = 31 * result + (metadata != null ? metadata.hashCode() : 0); + return result; + } +} diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/Registration.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/Registration.java new file mode 100644 index 00000000000..143cc9f4913 --- /dev/null +++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/Registration.java @@ -0,0 +1,53 @@ +/* + * 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.registry.support; + +import java.util.Map; + +/** + * The Registration + * + * @since 2.6.6 + */ +public interface Registration { + + /** + * @return The service name + */ + String getServiceName(); + + /** + * @return The IP address + */ + String getIp(); + + /** + * @return The service port + */ + int getPort(); + + /** + * @return The read-only metadata + */ + Map getMetadata(); + + @Override + boolean equals(Object o); + + @Override + int hashCode(); +} diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/ServiceInstanceRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/ServiceInstanceRegistry.java new file mode 100644 index 00000000000..e2eef7084ac --- /dev/null +++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/ServiceInstanceRegistry.java @@ -0,0 +1,475 @@ +/* + * 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.registry.support; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.logger.Logger; +import com.alibaba.dubbo.common.logger.LoggerFactory; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.common.utils.StringUtils; +import com.alibaba.dubbo.common.utils.UrlUtils; +import com.alibaba.dubbo.registry.NotifyListener; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import static com.alibaba.dubbo.common.Constants.CONFIGURATORS_CATEGORY; +import static com.alibaba.dubbo.common.Constants.CONSUMERS_CATEGORY; +import static com.alibaba.dubbo.common.Constants.PROVIDERS_CATEGORY; +import static com.alibaba.dubbo.common.Constants.ROUTERS_CATEGORY; +import static java.lang.Long.getLong; +import static java.lang.System.getProperty; + +/** + * {@link FailbackRegistry} extension that is used as the Oriented Service Instance registration, for + * + * @param The actual type of service instance + * @since 2.6.6 + */ +public abstract class ServiceInstanceRegistry extends FailbackRegistry { + + /** + * All supported categories + */ + private static final String[] ALL_SUPPORTED_CATEGORIES = of( + PROVIDERS_CATEGORY, + CONSUMERS_CATEGORY, + ROUTERS_CATEGORY, + CONFIGURATORS_CATEGORY + ); + + private static final int CATEGORY_INDEX = 0; + + private static final int SERVICE_INTERFACE_INDEX = CATEGORY_INDEX + 1; + + private static final int SERVICE_VERSION_INDEX = SERVICE_INTERFACE_INDEX + 1; + + private static final int SERVICE_GROUP_INDEX = SERVICE_VERSION_INDEX + 1; + + private static final String WILDCARD = "*"; + + /** + * The separator for service name + */ + private static final String SERVICE_NAME_SEPARATOR = getProperty("dubbo.service.name.separator", ":"); + + /** + * The interval in second of lookup service names(only for Dubbo-OPS) + */ + private static final long LOOKUP_INTERVAL = getLong("dubbo.service.names.lookup.interval", 30); + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + /** + * {@link ScheduledExecutorService} lookup service names(only for Dubbo-OPS) + */ + private volatile ScheduledExecutorService serviceNamesScheduler; + + public ServiceInstanceRegistry(URL url) { + super(url); + } + + @Override + protected final void doRegister(URL url) { + String serviceName = getServiceName(url); + Registration registration = createRegistration(serviceName, url); + register(serviceName, toServiceInstance(registration), url); + } + + @Override + protected final void doUnregister(URL url) { + String serviceName = getServiceName(url); + Registration registration = createRegistration(serviceName, url); + deregister(serviceName, toServiceInstance(registration), url); + } + + @Override + protected final void doSubscribe(URL url, NotifyListener listener) { + Set serviceNames = getServiceNames(url, listener); + doSubscribe(url, listener, serviceNames); + } + + @Override + protected void doUnsubscribe(URL url, NotifyListener listener) { + if (isAdminProtocol(url)) { + shutdownServiceNamesLookup(); + } + } + + /** + * Adapts {@link Registration} to an actual service instance + * + * @param registration {@link Registration} + * @return + */ + protected abstract S toServiceInstance(Registration registration); + + /** + * Adapts {@link S} to an {@link Registration} + * + * @param serviceInstance {@link S} + * @return an {@link Registration} + */ + protected abstract Registration toRegistration(S serviceInstance); + + /** + * Register a {@link S service instance} + * + * @param serviceName the service name + * @param serviceInstance {@link S service instance} + * @param url Dubbo's {@link URL} + */ + protected abstract void register(String serviceName, S serviceInstance, URL url); + + /** + * Deregister a {@link DubboRegistration Dubbol registration} + * + * @param serviceName the service name + * @param serviceInstance {@link S service instance} + * @param url Dubbo's {@link URL} + */ + protected abstract void deregister(String serviceName, S serviceInstance, URL url); + + private void doSubscribe(final URL url, final NotifyListener listener, final Set serviceNames) { + Collection serviceInstances = new LinkedList(); + + for (String serviceName : serviceNames) { + serviceInstances.addAll(findServiceInstances(serviceName)); + } + notifySubscriber(url, listener, serviceInstances); + } + + /** + * Notify the Healthy {@link DubboRegistration service instance} to subscriber. + * + * @param url {@link URL} + * @param listener {@link NotifyListener} + * @param serviceInstances all {@link S registrations} + */ + private void notifySubscriber(URL url, NotifyListener listener, Collection serviceInstances) { + Set healthyServiceInstances = new LinkedHashSet(serviceInstances); + // Healthy Instances + filterHealthyInstances(healthyServiceInstances); + List urls = buildURLs(url, healthyServiceInstances); + this.notify(url, listener, urls); + } + + private void filterHealthyInstances(Collection serviceInstances) { + filter(serviceInstances, new Filter() { + @Override + public boolean accept(S serviceInstance) { + return filterHealthyRegistration(serviceInstance); + } + }); + } + + /** + * Find the {@link Collection} of {@link S service instances} by the service name + * + * @param serviceName the service name + * @return a {@link Collection} of {@link S service instances} + */ + protected abstract Collection findServiceInstances(String serviceName); + + /** + * Filter Healthy the {@link S service instance} + * + * @param serviceInstance the {@link S service instance} + * @return if healthy , return true + */ + protected abstract boolean filterHealthyRegistration(S serviceInstance); + + private void shutdownServiceNamesLookup() { + if (serviceNamesScheduler != null) { + serviceNamesScheduler.shutdown(); + } + } + + private void scheduleServiceNamesLookup(final URL url, + final NotifyListener listener) { + if (serviceNamesScheduler == null) { + serviceNamesScheduler = Executors.newSingleThreadScheduledExecutor(); + serviceNamesScheduler.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + Set serviceNames = findAllServiceNames(); + filter(serviceNames, new Filter() { + @Override + public boolean accept(String serviceName) { + boolean accepted = false; + for (String category : ALL_SUPPORTED_CATEGORIES) { + String prefix = category + SERVICE_NAME_SEPARATOR; + if (serviceName.startsWith(prefix)) { + accepted = true; + break; + } + } + return accepted; + } + }); + doSubscribe(url, listener, serviceNames); + } + }, LOOKUP_INTERVAL, LOOKUP_INTERVAL, TimeUnit.SECONDS); + } + } + + /** + * Find all service names + * + * @return all service names + */ + protected abstract Set findAllServiceNames(); + + private List buildURLs(URL consumerURL, Collection serviceInstances) { + if (serviceInstances.isEmpty()) { + return Collections.emptyList(); + } + List urls = new LinkedList(); + for (S serviceInstance : serviceInstances) { + Registration registration = toRegistration(serviceInstance); + URL url = buildURL(registration); + if (UrlUtils.isMatch(consumerURL, url)) { + urls.add(url); + } + } + return urls; + } + + private URL buildURL(Registration registration) { + URL url = new URL(registration.getMetadata().get(Constants.PROTOCOL_KEY), + registration.getIp(), registration.getPort(), + registration.getMetadata()); + return url; + } + + /** + * Get the service names for Dubbo OPS + * + * @param url {@link URL} + * @return non-null + */ + private Set getSubscribedServiceNamesForOps(URL url) { + Set serviceNames = findAllServiceNames(); + filterServiceNames(serviceNames, url); + return serviceNames; + } + + private void filter(Collection collection, Filter filter) { + Iterator iterator = collection.iterator(); + while (iterator.hasNext()) { + T data = iterator.next(); + if (!filter.accept(data)) { // remove if not accept + iterator.remove(); + } + } + } + + private void filterServiceNames(Set serviceNames, URL url) { + + final String[] categories = getCategories(url); + + final String targetServiceInterface = url.getServiceInterface(); + + final String targetVersion = url.getParameter(Constants.VERSION_KEY); + + final String targetGroup = url.getParameter(Constants.GROUP_KEY); + + filter(serviceNames, new Filter() { + @Override + public boolean accept(String serviceName) { + // split service name to segments + // (required) segments[0] = category + // (required) segments[1] = serviceInterface + // (required) segments[2] = version + // (optional) segments[3] = group + String[] segments = getServiceSegments(serviceName); + int length = segments.length; + if (length < 4) { // must present 4 segments or more + return false; + } + + String category = getCategory(segments); + if (Arrays.binarySearch(categories, category) > -1) { // no match category + return false; + } + + String serviceInterface = getServiceInterface(segments); + if (!WILDCARD.equals(targetServiceInterface) + && !StringUtils.isEquals(targetServiceInterface, serviceInterface)) { // no match interface + return false; + } + + String version = getServiceVersion(segments); + if (!WILDCARD.equals(targetVersion) + && !StringUtils.isEquals(targetVersion, version)) { // no match service + // version + return false; + } + + String group = getServiceGroup(segments); + if (group != null && !WILDCARD.equals(targetGroup) + && !StringUtils.isEquals(targetGroup, group)) { // no match service + // group + return false; + } + + return true; + } + }); + } + + protected Registration createRegistration(String serviceName, URL url) { + // Append default category if absent + String category = url.getParameter(Constants.CATEGORY_KEY, + Constants.DEFAULT_CATEGORY); + URL newURL = url.addParameter(Constants.CATEGORY_KEY, category); + newURL = newURL.addParameter(Constants.PROTOCOL_KEY, url.getProtocol()); + String ip = NetUtils.getLocalHost(); + int port = newURL.getParameter(Constants.BIND_PORT_KEY, url.getPort()); + DubboRegistration registration = new DubboRegistration(); + registration.setServiceName(serviceName); + registration.setIp(ip); + registration.setPort(port); + registration.setMetadata(new LinkedHashMap(newURL.getParameters())); + + return registration; + } + + /** + * Get the categories from {@link URL} + * + * @param url {@link URL} + * @return non-null array + */ + private String[] getCategories(URL url) { + return Constants.ANY_VALUE.equals(url.getServiceInterface()) + ? ALL_SUPPORTED_CATEGORIES + : of(Constants.DEFAULT_CATEGORY); + } + + /** + * A filter + */ + private interface Filter { + + /** + * Tests whether or not the specified data should be accepted. + * + * @param data The data to be tested + * @return true if and only if data should be accepted + */ + boolean accept(T data); + + } + + /** + * Get the subscribed service names from the specified {@link URL url} + * + * @param url {@link URL} + * @param listener {@link NotifyListener} + * @return non-null + */ + private Set getServiceNames(URL url, NotifyListener listener) { + if (isAdminProtocol(url)) { + scheduleServiceNamesLookup(url, listener); + return getSubscribedServiceNamesForOps(url); + } else { + return getServiceNames(url); + } + } + + private Set getServiceNames(URL url) { + String[] categories = getCategories(url); + Set serviceNames = new LinkedHashSet(categories.length); + for (String category : categories) { + final String serviceName = getServiceName(url, category); + serviceNames.add(serviceName); + } + return serviceNames; + } + + private boolean isAdminProtocol(URL url) { + return Constants.ADMIN_PROTOCOL.equals(url.getProtocol()); + } + + /** + * Get the service name + * + * @param url {@link URL} + * @return non-null + */ + public static String getServiceName(URL url) { + String category = url.getParameter(Constants.CATEGORY_KEY, + Constants.DEFAULT_CATEGORY); + return getServiceName(url, category); + } + + private static String getServiceName(URL url, String category) { + StringBuilder serviceNameBuilder = new StringBuilder(category); + appendIfPresent(serviceNameBuilder, url, Constants.INTERFACE_KEY); + appendIfPresent(serviceNameBuilder, url, Constants.VERSION_KEY); + appendIfPresent(serviceNameBuilder, url, Constants.GROUP_KEY); + return serviceNameBuilder.toString(); + } + + private static void appendIfPresent(StringBuilder target, URL url, + String parameterName) { + String parameterValue = url.getParameter(parameterName); + appendIfPresent(target, parameterValue); + } + + public static String[] getServiceSegments(String serviceName) { + return serviceName.split(SERVICE_NAME_SEPARATOR); + } + + public static String getCategory(String[] segments) { + return segments[CATEGORY_INDEX]; + } + + public static String getServiceInterface(String[] segments) { + return segments[SERVICE_INTERFACE_INDEX]; + } + + public static String getServiceVersion(String[] segments) { + return segments[SERVICE_VERSION_INDEX]; + } + + public static String getServiceGroup(String[] segments) { + return segments.length > 4 ? segments[SERVICE_GROUP_INDEX] : null; + } + + private static T[] of(T... values) { + return values; + } + + private static void appendIfPresent(StringBuilder target, String parameterValue) { + if (StringUtils.isNotEmpty(parameterValue)) { + target.append(SERVICE_NAME_SEPARATOR).append(parameterValue); + } + } +} diff --git a/dubbo-registry/dubbo-registry-nacos/pom.xml b/dubbo-registry/dubbo-registry-nacos/pom.xml new file mode 100644 index 00000000000..d67333e8b5b --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/pom.xml @@ -0,0 +1,144 @@ + + + + dubbo-registry + com.alibaba + 2.6.6-SNAPSHOT + ../pom.xml + + 4.0.0 + + dubbo-registry-nacos + + + 0.6.2 + + + + + + com.alibaba + dubbo-registry-api + ${project.version} + true + + + + com.alibaba + dubbo-common + ${project.version} + true + + + + com.alibaba.nacos + nacos-client + ${nacos.version} + true + + + + + com.alibaba + dubbo-config-api + ${project.version} + test + + + + com.alibaba + dubbo-serialization-hessian2 + ${project.version} + test + + + + com.alibaba + dubbo-config-spring + ${project.version} + test + + + + com.alibaba + dubbo-rpc-dubbo + ${project.version} + test + + + + com.alibaba + dubbo-remoting-netty + ${project.version} + test + + + + ch.qos.logback + logback-classic + 1.2.3 + test + + + + + com.alibaba + dubbo-rpc-rest + ${project.version} + test + + + + org.jboss.resteasy + resteasy-jaxrs + test + + + + org.jboss.resteasy + resteasy-client + test + + + + org.jboss.resteasy + resteasy-netty4 + test + + + + javax.validation + validation-api + test + + + + org.jboss.resteasy + resteasy-jackson-provider + test + + + + org.jboss.resteasy + resteasy-jaxb-provider + test + + + + org.springframework + spring-test + test + + + + junit + junit + 4.12 + test + + + + + \ No newline at end of file diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistry.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistry.java new file mode 100644 index 00000000000..621e7b44bcc --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistry.java @@ -0,0 +1,198 @@ +/* + * 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.registry.nacos; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.registry.Registry; +import com.alibaba.dubbo.registry.support.Registration; +import com.alibaba.dubbo.registry.support.ServiceInstanceRegistry; +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.listener.EventListener; +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.api.naming.pojo.ListView; + +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * Nacos {@link Registry} + * + * @since 2.6.6 + */ +public class NacosRegistry extends ServiceInstanceRegistry { + + /** + * The pagination size of query for Nacos service names(only for Dubbo-OPS) + */ + private static final int PAGINATION_SIZE = Integer.getInteger("nacos.service.names.pagination.size", 100); + + private final NamingService namingService; + + private final ConcurrentMap nacosListeners; + + public NacosRegistry(URL url, NamingService namingService) { + super(url); + this.namingService = namingService; + this.nacosListeners = new ConcurrentHashMap(); + } + + + @Override + protected Instance toServiceInstance(Registration registration) { + Instance instance = new Instance(); + instance.setServiceName(registration.getServiceName()); + instance.setIp(registration.getIp()); + instance.setPort(registration.getPort()); + instance.setMetadata(registration.getMetadata()); + return instance; + } + + @Override + protected Registration toRegistration(final Instance serviceInstance) { + return new Registration() { + + @Override + public String getServiceName() { + return serviceInstance.getServiceName(); + } + + @Override + public String getIp() { + return serviceInstance.getIp(); + } + + @Override + public int getPort() { + return serviceInstance.getPort(); + } + + @Override + public Map getMetadata() { + return serviceInstance.getMetadata(); + } + }; + } + + @Override + protected void register(final String serviceName, final Instance serviceInstance, URL url) { + execute(new NamingServiceCallback() { + @Override + public void callback(NamingService namingService) throws NacosException { + namingService.registerInstance(serviceName, serviceInstance); + } + }); + } + + @Override + protected void deregister(final String serviceName, final Instance serviceInstance, URL url) { + execute(new NamingServiceCallback() { + @Override + public void callback(NamingService namingService) throws NacosException { + namingService.deregisterInstance(serviceName, serviceInstance.getIp(), serviceInstance.getPort()); + } + }); + } + + @Override + protected Collection findServiceInstances(final String serviceName) { + final Collection instances = new LinkedList(); + execute(new NamingServiceCallback() { + @Override + public void callback(NamingService namingService) throws NacosException { + instances.addAll(namingService.getAllInstances(serviceName)); + } + }); + return instances; + } + + @Override + protected boolean filterHealthyRegistration(Instance serviceInstance) { + return serviceInstance.isEnabled(); + } + + @Override + protected Set findAllServiceNames() { + final Set serviceNames = new LinkedHashSet(); + + execute(new NamingServiceCallback() { + @Override + public void callback(NamingService namingService) throws NacosException { + + int pageIndex = 1; + ListView listView = namingService.getServicesOfServer(pageIndex, PAGINATION_SIZE); + // First page data + List firstPageData = listView.getData(); + // Append first page into list + serviceNames.addAll(firstPageData); + // the total count + int count = listView.getCount(); + // the number of pages + int pageNumbers = count / PAGINATION_SIZE; + int remainder = count % PAGINATION_SIZE; + // remain + if (remainder > 0) { + pageNumbers += 1; + } + // If more than 1 page + while (pageIndex < pageNumbers) { + listView = namingService.getServicesOfServer(++pageIndex, PAGINATION_SIZE); + serviceNames.addAll(listView.getData()); + } + + } + }); + + return serviceNames; + } + + @Override + public boolean isAvailable() { + return "UP".equals(namingService.getServerStatus()); + } + + private void execute(NamingServiceCallback callback) { + try { + callback.callback(namingService); + } catch (NacosException e) { + if (logger.isErrorEnabled()) { + logger.error(e.getErrMsg(), e); + } + } + } + + /** + * {@link NamingService} Callback + */ + interface NamingServiceCallback { + + /** + * Callback + * + * @param namingService {@link NamingService} + * @throws NacosException + */ + void callback(NamingService namingService) throws NacosException; + + } +} diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactory.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactory.java new file mode 100644 index 00000000000..56de76076d4 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactory.java @@ -0,0 +1,108 @@ +/* + * 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.registry.nacos; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.registry.Registry; +import com.alibaba.dubbo.registry.RegistryFactory; +import com.alibaba.dubbo.registry.support.AbstractRegistryFactory; +import com.alibaba.nacos.api.NacosFactory; +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.client.naming.utils.StringUtils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Properties; + +import static com.alibaba.dubbo.common.Constants.BACKUP_KEY; +import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY; +import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME; +import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT; +import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE; +import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY; +import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR; +import static com.alibaba.nacos.client.naming.utils.UtilAndComs.NACOS_NAMING_LOG_NAME; + +/** + * Nacos {@link RegistryFactory} + * + * @since 2.6.6 + */ +public class NacosRegistryFactory extends AbstractRegistryFactory { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + protected Registry createRegistry(URL url) { + return new NacosRegistry(url, buildNamingService(url)); + } + + private NamingService buildNamingService(URL url) { + Properties nacosProperties = buildNacosProperties(url); + NamingService namingService = null; + try { + namingService = NacosFactory.createNamingService(nacosProperties); + } catch (NacosException e) { + if (logger.isErrorEnabled()) { + logger.error(e.getErrMsg(), e); + } + throw new IllegalStateException(e); + } + return namingService; + } + + private Properties buildNacosProperties(URL url) { + Properties properties = new Properties(); + setServerAddr(url, properties); + setProperties(url, properties); + return properties; + } + + private void setServerAddr(URL url, Properties properties) { + StringBuilder serverAddrBuilder = + new StringBuilder(url.getHost()) // Host + .append(":") + .append(url.getPort()); // Port + + // Append backup parameter as other servers + String backup = url.getParameter(BACKUP_KEY); + if (backup != null) { + serverAddrBuilder.append(",").append(backup); + } + + String serverAddr = serverAddrBuilder.toString(); + properties.put(SERVER_ADDR, serverAddr); + } + + private void setProperties(URL url, Properties properties) { + putPropertyIfAbsent(url, properties, NAMESPACE); + putPropertyIfAbsent(url, properties, NACOS_NAMING_LOG_NAME); + putPropertyIfAbsent(url, properties, ENDPOINT); + putPropertyIfAbsent(url, properties, NAMESPACE); + putPropertyIfAbsent(url, properties, ACCESS_KEY); + putPropertyIfAbsent(url, properties, SECRET_KEY); + putPropertyIfAbsent(url, properties, CLUSTER_NAME); + } + + private void putPropertyIfAbsent(URL url, Properties properties, String propertyName) { + String propertyValue = url.getParameter(propertyName); + if (StringUtils.isNotEmpty(propertyValue)) { + properties.setProperty(propertyName, propertyValue); + } + } +} diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory b/dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory new file mode 100644 index 00000000000..370cd4abdcf --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory @@ -0,0 +1 @@ +nacos=com.alibaba.dubbo.registry.nacos.NacosRegistryFactory \ No newline at end of file diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java new file mode 100644 index 00000000000..c61dcb5127a --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java @@ -0,0 +1,59 @@ +/* + * 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.demo.consumer; + +import com.alibaba.dubbo.config.annotation.Reference; +import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; +import com.alibaba.dubbo.demo.service.DemoService; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.PropertySource; + +import javax.annotation.PostConstruct; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +/** + * {@link DemoService} consumer demo + */ +@EnableDubbo +@PropertySource(value = "classpath:/consumer-config.properties") +public class DemoServiceConsumerBootstrap { + + @Reference(version = "${demo.service.version}") + private DemoService demoService; + + @Reference(version = "${demo.service.version}", protocol = "rest") + private DemoService restDemoService; + + @PostConstruct + public void init() throws InterruptedException { + for (int j = 0; j < 10; j++) { + System.out.println(demoService.sayName("小马哥(mercyblitz)")); + System.out.println(restDemoService.sayName("小马哥(mercyblitz)")); + } + Thread.sleep(TimeUnit.SECONDS.toMillis(5)); + } + + public static void main(String[] args) throws IOException { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(DemoServiceConsumerBootstrap.class); + context.refresh(); + System.in.read(); + context.close(); + } +} diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java new file mode 100644 index 00000000000..65b7befb7a6 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java @@ -0,0 +1,42 @@ +/* + * 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.demo.consumer; + +import com.alibaba.dubbo.demo.service.DemoService; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import java.io.IOException; + +/** + * {@link DemoService} consumer demo XML bootstrap + */ +public class DemoServiceConsumerXmlBootstrap { + + public static void main(String[] args) throws IOException { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(); + context.setConfigLocation("/META-INF/spring/dubbo-consumer-context.xml"); + context.refresh(); + System.out.println("DemoService consumer (XML) is starting..."); + DemoService demoService = context.getBean("demoService", DemoService.class); + for (int i = 0; i < 10; i++) { + System.out.println(demoService.sayName("小马哥(mercyblitz)")); + } + System.in.read(); + context.close(); + } +} diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderBootstrap.java new file mode 100644 index 00000000000..f9cd79742db --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderBootstrap.java @@ -0,0 +1,41 @@ +/* + * 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.demo.provider; + +import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; +import com.alibaba.dubbo.demo.service.DemoService; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.PropertySource; + +import java.io.IOException; + +/** + * {@link DemoService} provider demo + */ +@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.demo.service") +@PropertySource(value = "classpath:/provider-config.properties") +public class DemoServiceProviderBootstrap { + + public static void main(String[] args) throws IOException { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(DemoServiceProviderBootstrap.class); + context.refresh(); + System.out.println("DemoService provider is starting..."); + System.in.read(); + } +} diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderXmlBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderXmlBootstrap.java new file mode 100644 index 00000000000..964adbcb5cf --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderXmlBootstrap.java @@ -0,0 +1,37 @@ +/* + * 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.demo.provider; + +import com.alibaba.dubbo.demo.service.DemoService; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import java.io.IOException; + +/** + * {@link DemoService} provider demo XML bootstrap + */ +public class DemoServiceProviderXmlBootstrap { + + public static void main(String[] args) throws IOException { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(); + context.setConfigLocation("/META-INF/spring/dubbo-provider-context.xml"); + context.refresh(); + System.out.println("DemoService provider (XML) is starting..."); + System.in.read(); + } +} diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DefaultService.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DefaultService.java new file mode 100644 index 00000000000..0ff9ada86f7 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DefaultService.java @@ -0,0 +1,46 @@ +/* + * 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.demo.service; + +import com.alibaba.dubbo.config.annotation.Service; +import com.alibaba.dubbo.rpc.RpcContext; + +import org.springframework.beans.factory.annotation.Value; + + +/** + * Default {@link DemoService} + * + * @since 2.6.5 + */ +@Service(version = "${demo.service.version}") +public class DefaultService implements DemoService { + + @Value("${demo.service.name}") + private String serviceName; + + public String sayName(String name) { + RpcContext rpcContext = RpcContext.getContext(); + return String.format("Service [name :%s , protocol: %s , port : %d] %s(\"%s\") : Hello,%s", + serviceName, + rpcContext.getUrl().getProtocol(), + rpcContext.getLocalPort(), + rpcContext.getMethodName(), + name, + name); + } +} diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DemoService.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DemoService.java new file mode 100644 index 00000000000..381540e1266 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DemoService.java @@ -0,0 +1,34 @@ +/* + * 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.demo.service; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; + +/** + * DemoService + * + * @since 2.6.5 + */ +@Path("/demo-service") +public interface DemoService { + + @GET + String sayName(@QueryParam("name") String name); + +} \ No newline at end of file diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactoryTest.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactoryTest.java new file mode 100644 index 00000000000..8f7a1525050 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactoryTest.java @@ -0,0 +1,25 @@ +/* + * 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.registry.nacos; + +/** + * {@link NacosRegistryFactory} Test + * + * @since 2.6.5 + */ +public class NacosRegistryFactoryTest { +} diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryTest.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryTest.java new file mode 100644 index 00000000000..3ff055b6554 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryTest.java @@ -0,0 +1,32 @@ +/* + * 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.registry.nacos; + +/** + * {@link NacosRegistry} Test + * + * @since 2.6.5 + */ +public class NacosRegistryTest { + + // Test case Dubbo OPS : + // URL : admin://30.5.124.12?category=providers,consumers,routers,configurators&check=false&classifier=*&enabled=*&group=*&interface=*&version=* + public void testDoSubscribeForDubboOps() { + + } + +} diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-consumer-context.xml b/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-consumer-context.xml new file mode 100644 index 00000000000..0d47053d0d4 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-consumer-context.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-provider-context.xml b/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-provider-context.xml new file mode 100644 index 00000000000..acf08a50370 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-provider-context.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/resources/consumer-config.properties b/dubbo-registry/dubbo-registry-nacos/src/test/resources/consumer-config.properties new file mode 100644 index 00000000000..d32e6e8a64e --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/resources/consumer-config.properties @@ -0,0 +1,6 @@ +## Dubbo Application info +dubbo.application.name=dubbo-consumer-demo +## Nacos registry address +dubbo.registry.address=nacos://127.0.0.1:8848 +# @Reference version +demo.service.version=1.0.0 \ No newline at end of file diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/resources/provider-config.properties b/dubbo-registry/dubbo-registry-nacos/src/test/resources/provider-config.properties new file mode 100644 index 00000000000..e2dd335b0ed --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/resources/provider-config.properties @@ -0,0 +1,14 @@ +## Dubbo Application info +dubbo.application.name=dubbo-provider-demo +## Nacos registry address +dubbo.registry.protocol=nacos +dubbo.registry.address=127.0.0.1:8848 +## Exports multiple protocols +### Dubbo Protocol using random port +dubbo.protocols.dubbo.port=-1 +### REST protocol +dubbo.protocols.rest.port=9090 +dubbo.protocols.rest.server=netty +# Provider @Service info +demo.service.version=1.0.0 +demo.service.name=demoService \ No newline at end of file diff --git a/dubbo-registry/pom.xml b/dubbo-registry/pom.xml index b268a88d785..fe3a7f86a14 100644 --- a/dubbo-registry/pom.xml +++ b/dubbo-registry/pom.xml @@ -34,5 +34,6 @@ dubbo-registry-multicast dubbo-registry-zookeeper dubbo-registry-redis + dubbo-registry-nacos From debeb889269d1912e849c80321be31d14585ee15 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Wed, 30 Jan 2019 18:51:16 +0800 Subject: [PATCH 34/38] Polish apache/incubator-dubbo#3251 : @Service supports the hierarchical interface --- .../annotation/ServiceAnnotationBeanPostProcessor.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 677710048fe..0c2fc64406c 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 @@ -315,8 +315,9 @@ private Class resolveServiceInterfaceClass(Class annotatedServiceBeanClass } if (interfaceClass == null) { - - Class[] allInterfaces = annotatedServiceBeanClass.getInterfaces(); + // Find all interfaces from the annotated class + // To resolve an issue : https://github.com/apache/incubator-dubbo/issues/3251 + Class[] allInterfaces = ClassUtils.getAllInterfacesForClass(annotatedServiceBeanClass); if (allInterfaces.length > 0) { interfaceClass = allInterfaces[0]; From 31ecb9dccfa11f7eb4ad9462ca4622fda43b677b Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 22 Feb 2019 13:31:06 +0800 Subject: [PATCH 35/38] Polish apache/incubator-dubbo#3275 : ReferenceBeanInvocationHandler does not throw the actual exception --- .../ReferenceAnnotationBeanPostProcessor.java | 10 ++++++- .../DubboComponentScanRegistrarTest.java | 26 +++++++++++++++++++ .../annotation/provider/DemoServiceImpl.java | 7 +---- 3 files changed, 36 insertions(+), 7 deletions(-) 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 467810de0b2..3dc3e9eb622 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 @@ -32,6 +32,7 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Collection; @@ -155,7 +156,14 @@ private ReferenceBeanInvocationHandler(ReferenceBean referenceBean) { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - return method.invoke(bean, args); + Object result = null; + try { + result = method.invoke(bean, args); + } catch (InvocationTargetException e) { + // re-throws the actual Exception. + throw e.getTargetException(); + } + return result; } private void init() { diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java index 54d6c972bad..20a1504ea20 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java @@ -111,5 +111,31 @@ public void test() { } + @Test(expected = UnsupportedOperationException.class) + public void testOnException() { + + AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext(); + + providerContext.register(ProviderConfiguration.class); + + providerContext.refresh(); + + AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(); + + consumerContext.register(ConsumerConfiguration.class); + + consumerContext.refresh(); + + ConsumerConfiguration.Child child = consumerContext.getBean(ConsumerConfiguration.Child.class); + + // From Child + DemoService demoService = child.getDemoServiceFromChild(); + + demoService.getBox(); + + providerContext.close(); + consumerContext.close(); + } + } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java index d5e48f1dff1..84c451a61fa 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java @@ -45,11 +45,6 @@ public String sayName(String name) { @Override public Box getBox() { - return new Box() { - @Override - public String getName() { - return "MyBox"; - } - }; + throw new UnsupportedOperationException("For Purposes!"); } } From 7afef6a0a692d9a9efce3943d6e48de4af793b97 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 22 Feb 2019 14:18:22 +0800 Subject: [PATCH 36/38] Polish apache/incubator-dubbo#3429 : Fix the NPE --- .../annotation/ReferenceAnnotationBeanPostProcessor.java | 4 ++++ 1 file changed, 4 insertions(+) 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 3dc3e9eb622..e8be4c0decb 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 @@ -158,6 +158,10 @@ private ReferenceBeanInvocationHandler(ReferenceBean referenceBean) { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; try { + if (bean == null) { // If the bean is not initialized, invoke init() + // issue: https://github.com/apache/incubator-dubbo/issues/3429 + init(); + } result = method.invoke(bean, args); } catch (InvocationTargetException e) { // re-throws the actual Exception. From 3238d885eb0d713ebdde97038ff8262db7a7d1ad Mon Sep 17 00:00:00 2001 From: min Date: Mon, 25 Feb 2019 10:25:20 +0800 Subject: [PATCH 37/38] add license header --- dubbo-registry/dubbo-registry-nacos/pom.xml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/dubbo-registry/dubbo-registry-nacos/pom.xml b/dubbo-registry/dubbo-registry-nacos/pom.xml index d67333e8b5b..00feb872356 100644 --- a/dubbo-registry/dubbo-registry-nacos/pom.xml +++ b/dubbo-registry/dubbo-registry-nacos/pom.xml @@ -1,4 +1,20 @@ + @@ -141,4 +157,4 @@ - \ No newline at end of file + From a5e439f6d30d036dd680e00fc3489e656a1bceec Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Mon, 25 Feb 2019 16:21:54 +0800 Subject: [PATCH 38/38] Polish apache/incubator-dubbo#3296 : Supports Docker --- .../registry/support/ServiceInstanceRegistry.java | 5 ++--- dubbo-registry/dubbo-registry-nacos/pom.xml | 2 +- .../alibaba/dubbo/rpc/protocol/rest/RestProtocol.java | 10 ++++++++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/ServiceInstanceRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/ServiceInstanceRegistry.java index e2eef7084ac..d6b1d8736d3 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/ServiceInstanceRegistry.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/ServiceInstanceRegistry.java @@ -20,7 +20,6 @@ import com.alibaba.dubbo.common.URL; import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; -import com.alibaba.dubbo.common.utils.NetUtils; import com.alibaba.dubbo.common.utils.StringUtils; import com.alibaba.dubbo.common.utils.UrlUtils; import com.alibaba.dubbo.registry.NotifyListener; @@ -349,8 +348,8 @@ protected Registration createRegistration(String serviceName, URL url) { Constants.DEFAULT_CATEGORY); URL newURL = url.addParameter(Constants.CATEGORY_KEY, category); newURL = newURL.addParameter(Constants.PROTOCOL_KEY, url.getProtocol()); - String ip = NetUtils.getLocalHost(); - int port = newURL.getParameter(Constants.BIND_PORT_KEY, url.getPort()); + String ip = url.getHost(); + int port = url.getPort(); DubboRegistration registration = new DubboRegistration(); registration.setServiceName(serviceName); registration.setIp(ip); diff --git a/dubbo-registry/dubbo-registry-nacos/pom.xml b/dubbo-registry/dubbo-registry-nacos/pom.xml index d67333e8b5b..e93085cf8a9 100644 --- a/dubbo-registry/dubbo-registry-nacos/pom.xml +++ b/dubbo-registry/dubbo-registry-nacos/pom.xml @@ -70,7 +70,7 @@ com.alibaba - dubbo-remoting-netty + dubbo-remoting-netty4 ${project.version} test diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/com/alibaba/dubbo/rpc/protocol/rest/RestProtocol.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/com/alibaba/dubbo/rpc/protocol/rest/RestProtocol.java index 78b5debc960..be4225cdcfc 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/com/alibaba/dubbo/rpc/protocol/rest/RestProtocol.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/com/alibaba/dubbo/rpc/protocol/rest/RestProtocol.java @@ -25,6 +25,7 @@ import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.StaticContext; import com.alibaba.dubbo.rpc.protocol.AbstractProxyProtocol; + import org.apache.http.HeaderElement; import org.apache.http.HeaderElementIterator; import org.apache.http.HttpResponse; @@ -231,8 +232,13 @@ public void destroy() { } protected String getContextPath(URL url) { - int pos = url.getPath().lastIndexOf("/"); - return pos > 0 ? url.getPath().substring(0, pos) : ""; + String path = url.getPath(); + if (path != null) { + int pos = url.getPath().lastIndexOf("/"); + return pos > 0 ? url.getPath().substring(0, pos) : ""; + } else { + return ""; + } } protected class ConnectionMonitor extends Thread {