From 4f3454002414f19ee07664c731a02aa30c4d8b27 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Tue, 20 Mar 2018 11:08:56 +0800 Subject: [PATCH 01/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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 88f3af3261aa4bc9f5342da5e894cacefd98f891 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 8 Jun 2018 13:02:15 +0800 Subject: [PATCH 08/20] Add 2.7.x branch --- dump.rdb | Bin 0 -> 132 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 dump.rdb diff --git a/dump.rdb b/dump.rdb new file mode 100644 index 0000000000000000000000000000000000000000..e1a82f7562cc719e8e3625d3ed3c360bbf03c9b4 GIT binary patch literal 132 zcmWG?b@2=~Ffg$A#aWb^l3A= Date: Fri, 8 Jun 2018 13:03:16 +0800 Subject: [PATCH 09/20] Remove useless fiels --- dump.rdb | Bin 132 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 dump.rdb diff --git a/dump.rdb b/dump.rdb deleted file mode 100644 index e1a82f7562cc719e8e3625d3ed3c360bbf03c9b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 132 zcmWG?b@2=~Ffg$A#aWb^l3A= Date: Fri, 22 Jun 2018 22:53:54 +0800 Subject: [PATCH 10/20] RestSevice demo code --- dubbo-rpc/dubbo-rpc-springmvc/pom.xml | 43 ++++++++++++ .../webmvc/annotation/EnableRestService.java | 37 ++++++++++ .../spring/webmvc/annotation/RestService.java | 34 ++++++++++ .../annotation/RestServiceConfiguration.java | 43 ++++++++++++ .../annotation/RestServiceHandlerAdapter.java | 67 +++++++++++++++++++ .../annotation/RestServiceHandlerMapping.java | 47 +++++++++++++ ...erviceHandlerMethodReturnValueHandler.java | 54 +++++++++++++++ dubbo-rpc/pom.xml | 1 + 8 files changed, 326 insertions(+) create mode 100755 dubbo-rpc/dubbo-rpc-springmvc/pom.xml create mode 100755 dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/EnableRestService.java create mode 100755 dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/RestService.java create mode 100755 dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/RestServiceConfiguration.java create mode 100755 dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerAdapter.java create mode 100755 dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerMapping.java create mode 100755 dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerMethodReturnValueHandler.java diff --git a/dubbo-rpc/dubbo-rpc-springmvc/pom.xml b/dubbo-rpc/dubbo-rpc-springmvc/pom.xml new file mode 100755 index 00000000000..400b4e966ea --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-springmvc/pom.xml @@ -0,0 +1,43 @@ + + + + dubbo-rpc + com.alibaba + 2.7.0-SNAPSHOT + + 4.0.0 + + dubbo-rpc-springmvc + jar + ${project.artifactId} + The Spring MVC rpc module of dubbo project + + false + + + + + com.alibaba + dubbo-rpc-api + ${project.parent.version} + + + org.springframework + spring-context + + + + javax.servlet + javax.servlet-api + provided + + + + org.springframework + spring-webmvc + + + + \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/EnableRestService.java b/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/EnableRestService.java new file mode 100755 index 00000000000..efd8aa9385c --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/EnableRestService.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.rpc.protocol.spring.webmvc.annotation; + +import org.springframework.context.annotation.Import; + +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; + +/** + * Enable {@link RestService Rest Service} + * + * @since 2.7.0 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Import(RestServiceConfiguration.class) +public @interface EnableRestService { +} diff --git a/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/RestService.java b/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/RestService.java new file mode 100755 index 00000000000..62aa81c5eec --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/RestService.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.rpc.protocol.spring.webmvc.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; + +/** + * Rest Service Annotation + * + * @since 2.7.0 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface RestService { +} diff --git a/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/RestServiceConfiguration.java b/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/RestServiceConfiguration.java new file mode 100755 index 00000000000..2774ccd3267 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/RestServiceConfiguration.java @@ -0,0 +1,43 @@ +/* + * 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.rpc.protocol.spring.webmvc.annotation; + +import com.alibaba.dubbo.rpc.protocol.spring.webmvc.method.annotation.RestServiceHandlerAdapter; +import com.alibaba.dubbo.rpc.protocol.spring.webmvc.method.annotation.RestServiceHandlerMapping; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * {@link RestService} + * + * @since 2.7.0 + */ +@Configuration +public class RestServiceConfiguration { + + @Bean + public RestServiceHandlerMapping restServiceHandlerMapping() { + return new RestServiceHandlerMapping(); + } + + @Bean + public RestServiceHandlerAdapter restServiceHandlerAdapter(){ + return new RestServiceHandlerAdapter(); + } + + +} diff --git a/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerAdapter.java b/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerAdapter.java new file mode 100755 index 00000000000..37fde952a98 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerAdapter.java @@ -0,0 +1,67 @@ +/* + * 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.rpc.protocol.spring.webmvc.method.annotation; + +import com.alibaba.dubbo.rpc.protocol.spring.webmvc.annotation.RestService; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.util.ClassUtils; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.method.support.HandlerMethodReturnValueHandler; +import org.springframework.web.servlet.HandlerAdapter; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; +import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor; + +import java.util.LinkedList; +import java.util.List; + +/** + * {@link RestService @RestService} {@link HandlerAdapter} + * + * @since 2.7.0 + */ +public class RestServiceHandlerAdapter extends RequestMappingHandlerAdapter { + + protected boolean supportsInternal(HandlerMethod handlerMethod) { + Class beanType = handlerMethod.getBeanType(); + return AnnotatedElementUtils.hasAnnotation(beanType, RestService.class); + } + + @Override + public void afterPropertiesSet() { + + super.afterPropertiesSet(); + + final List allReturnValueHandlers = getReturnValueHandlers(); + + final List restReturnValueHandlers = new LinkedList(); + + for (HandlerMethodReturnValueHandler returnValueHandler : allReturnValueHandlers) { + + if (ClassUtils.isAssignableValue(RequestResponseBodyMethodProcessor.class, returnValueHandler)) { + + RequestResponseBodyMethodProcessor delegate = (RequestResponseBodyMethodProcessor) returnValueHandler; + HandlerMethodReturnValueHandler restReturnValueHandler = new RestServiceHandlerMethodReturnValueHandler(delegate); + restReturnValueHandlers.add(restReturnValueHandler); + } + + } + + setReturnValueHandlers(restReturnValueHandlers); + + } + +} diff --git a/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerMapping.java b/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerMapping.java new file mode 100755 index 00000000000..79f8973b573 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerMapping.java @@ -0,0 +1,47 @@ +/* + * 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.rpc.protocol.spring.webmvc.method.annotation; + +import com.alibaba.dubbo.rpc.protocol.spring.webmvc.annotation.RestService; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.HandlerMapping; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; + +/** + * {@link RestService @RestService} {@link HandlerMapping} implementation that is compatible with + * Spring Web MVC standard {@link RequestMapping @RequestMapping} annotation. + * + * @see RequestMapping + * @see RequestMappingHandlerMapping + * @since 2.7.0 + */ +public class RestServiceHandlerMapping extends RequestMappingHandlerMapping { + + /** + * Default Constructor with highest precedence order. + */ + public RestServiceHandlerMapping() { + setOrder(HIGHEST_PRECEDENCE); + } + + @Override + protected boolean isHandler(Class beanType) { + return AnnotatedElementUtils.hasAnnotation(beanType, RestService.class); + } + +} diff --git a/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerMethodReturnValueHandler.java b/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerMethodReturnValueHandler.java new file mode 100755 index 00000000000..df7df609780 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerMethodReturnValueHandler.java @@ -0,0 +1,54 @@ +/* + * 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.rpc.protocol.spring.webmvc.method.annotation; + +import com.alibaba.dubbo.rpc.protocol.spring.webmvc.annotation.RestService; +import org.springframework.core.MethodParameter; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodReturnValueHandler; +import org.springframework.web.method.support.ModelAndViewContainer; +import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor; + +/** + * {@link RestService @RestService} {@link HandlerMethodReturnValueHandler} implementation + * + * @since 2.7.0 + */ +public class RestServiceHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler { + + private final RequestResponseBodyMethodProcessor processor; + + public RestServiceHandlerMethodReturnValueHandler(RequestResponseBodyMethodProcessor processor) { + this.processor = processor; + } + + @Override + public boolean supportsReturnType(MethodParameter returnType) { + Class serviceClass = returnType.getDeclaringClass(); + return AnnotatedElementUtils.hasAnnotation(serviceClass, RestService.class); + } + + @Override + public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, + NativeWebRequest webRequest) throws Exception { + + processor.handleReturnValue(returnValue, returnType, mavContainer, webRequest); + + } + +} diff --git a/dubbo-rpc/pom.xml b/dubbo-rpc/pom.xml index a9afbf91613..4b2f33b87ef 100644 --- a/dubbo-rpc/pom.xml +++ b/dubbo-rpc/pom.xml @@ -40,5 +40,6 @@ dubbo-rpc-memcached dubbo-rpc-redis dubbo-rpc-rest + dubbo-rpc-springmvc From 23afeac4bfbb16dd3a3e79e0ab4ab14e742d357b Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Thu, 14 Mar 2019 14:24:26 +0800 Subject: [PATCH 11/20] Polish apache/incubator-dubbo#3429 : Fix The NPE issue --- .../ReferenceAnnotationBeanPostProcessor.java | 34 +++++++++++++------ .../AnnotationPropertyValuesAdapterTest.java | 14 ++++---- .../annotation/ReferenceBeanBuilderTest.java | 16 ++++----- .../annotation/provider/DemoServiceImpl.java | 7 +--- 4 files changed, 39 insertions(+), 32 deletions(-) diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java index 82fb9b25eb0..8a1ab20c8c1 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java @@ -16,6 +16,17 @@ */ package org.apache.dubbo.config.spring.beans.factory.annotation; +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; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.spring.ReferenceBean; import org.apache.dubbo.config.spring.ServiceBean; @@ -30,16 +41,6 @@ import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - /** * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation * that Consumer service {@link Reference} annotated fields @@ -155,7 +156,18 @@ 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 { + 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. + throw e.getTargetException(); + } + return result; } private void init() { diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapterTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapterTest.java index 0baa7bbe450..15d9fb9e550 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapterTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapterTest.java @@ -17,6 +17,12 @@ package org.apache.dubbo.config.spring.beans.factory.annotation; +import static org.springframework.util.StringUtils.arrayToCommaDelimitedString; + +import java.lang.reflect.Field; +import java.util.LinkedHashMap; +import java.util.Map; + import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.spring.ReferenceBean; @@ -31,12 +37,6 @@ 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 * @@ -96,7 +96,7 @@ public Map convert(String[] source) { Assert.assertEquals("dubbo://localhost:12345", referenceBean.getUrl()); Assert.assertEquals("client", referenceBean.getClient()); Assert.assertEquals(true, referenceBean.isGeneric()); - Assert.assertEquals(true, referenceBean.isInjvm()); + Assert.assertNull(referenceBean.isInjvm()); Assert.assertEquals(false, referenceBean.isCheck()); Assert.assertEquals(true, referenceBean.isInit()); Assert.assertEquals(true, referenceBean.getLazy()); diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java index 27f6c9663ed..9018bb0e4b5 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java @@ -17,6 +17,13 @@ package org.apache.dubbo.config.spring.beans.factory.annotation; +import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; +import static org.springframework.util.ReflectionUtils.findField; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.spring.ReferenceBean; @@ -28,13 +35,6 @@ 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 * @@ -81,7 +81,7 @@ public void testBuild() throws Exception { Assert.assertEquals("dubbo://localhost:12345", referenceBean.getUrl()); Assert.assertEquals("client", referenceBean.getClient()); Assert.assertEquals(true, referenceBean.isGeneric()); - Assert.assertEquals(true, referenceBean.isInjvm()); + Assert.assertNull(referenceBean.isInjvm()); Assert.assertEquals(false, referenceBean.isCheck()); Assert.assertEquals(null, referenceBean.isInit()); Assert.assertEquals(true, referenceBean.getLazy()); diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java index eb12225588f..3aa1e86f4e6 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/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 16bc3833e2b781d3a4de057118d27411bf5cbfbb Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Thu, 14 Mar 2019 14:38:39 +0800 Subject: [PATCH 12/20] Polish apache/incubator-dubbo#1306 : @Reference bean name conflict --- .../annotation/AnnotationBeanNameBuilder.java | 142 ++++++++++++++++++ .../ReferenceAnnotationBeanPostProcessor.java | 4 +- .../ServiceAnnotationBeanPostProcessor.java | 27 ++-- .../annotation/ServiceBeanNameBuilder.java | 113 -------------- ...ava => AnnotationBeanNameBuilderTest.java} | 53 ++++--- 5 files changed, 190 insertions(+), 149 deletions(-) create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilder.java delete mode 100644 dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java rename dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/{ServiceBeanNameBuilderTest.java => AnnotationBeanNameBuilderTest.java} (51%) diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilder.java new file mode 100644 index 00000000000..8a406f529ee --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/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 org.apache.dubbo.config.spring.beans.factory.annotation; + +import static org.apache.dubbo.common.Constants.CONSUMERS_CATEGORY; +import static org.apache.dubbo.common.Constants.DEFAULT_PROTOCOL; +import static org.apache.dubbo.common.Constants.PROVIDERS_CATEGORY; +import static org.apache.dubbo.config.spring.util.AnnotationUtils.resolveInterfaceName; +import static org.springframework.util.StringUtils.arrayToCommaDelimitedString; +import static org.springframework.util.StringUtils.hasText; + +import org.apache.dubbo.common.Constants; +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.registry.Registry; + +import org.springframework.core.env.Environment; + +/** + * 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/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java index 8a1ab20c8c1..35f1e1d3c4a 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java @@ -188,7 +188,9 @@ protected String buildInjectedObjectCacheKey(Reference reference, Object bean, S 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/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java index bc5339b55dc..0a1c33818a3 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java @@ -16,6 +16,18 @@ */ package org.apache.dubbo.config.spring.beans.factory.annotation; +import static org.apache.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; +import static org.springframework.util.ClassUtils.resolveClassName; + +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.config.annotation.Service; @@ -51,18 +63,6 @@ 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 org.apache.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; -import static org.springframework.util.ClassUtils.resolveClassName; - /** * {@link Service} Annotation * {@link BeanDefinitionRegistryPostProcessor Bean Definition Registry Post Processor} @@ -289,8 +289,9 @@ 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(); diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java deleted file mode 100644 index 6cd712408be..00000000000 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java +++ /dev/null @@ -1,113 +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 org.apache.dubbo.config.spring.beans.factory.annotation; - -import org.apache.dubbo.config.annotation.Reference; -import org.apache.dubbo.config.annotation.Service; -import org.apache.dubbo.config.spring.ReferenceBean; -import org.apache.dubbo.config.spring.ServiceBean; - -import org.springframework.core.env.Environment; -import org.springframework.util.StringUtils; - -import static org.apache.dubbo.config.spring.util.AnnotationUtils.resolveInterfaceName; - - -/** - * Dubbo {@link Service @Service} Bean Builder - * - * @see Service - * @see Reference - * @see ServiceBean - * @see ReferenceBean - * @since 2.6.5 - */ -class ServiceBeanNameBuilder { - - private static final String SEPARATOR = ":"; - - private final String interfaceClassName; - - private final Environment environment; - - // Optional - private String version; - - private String group; - - private ServiceBeanNameBuilder(String interfaceClassName, Environment environment) { - this.interfaceClassName = interfaceClassName; - this.environment = environment; - } - - private ServiceBeanNameBuilder(Class interfaceClass, Environment environment) { - this(interfaceClass.getName(), environment); - } - - private ServiceBeanNameBuilder(Service service, Class interfaceClass, Environment environment) { - this(resolveInterfaceName(service, interfaceClass), environment); - this.group(service.group()); - this.version(service.version()); - } - - private ServiceBeanNameBuilder(Reference reference, Class interfaceClass, Environment environment) { - this(resolveInterfaceName(reference, interfaceClass), environment); - this.group(reference.group()); - this.version(reference.version()); - } - - public static ServiceBeanNameBuilder create(Class interfaceClass, Environment environment) { - return new ServiceBeanNameBuilder(interfaceClass, environment); - } - - public static ServiceBeanNameBuilder create(Service service, Class interfaceClass, Environment environment) { - return new ServiceBeanNameBuilder(service, interfaceClass, environment); - } - - public static ServiceBeanNameBuilder create(Reference reference, Class interfaceClass, Environment environment) { - return new ServiceBeanNameBuilder(reference, interfaceClass, environment); - } - - private static void append(StringBuilder builder, String value) { - if (StringUtils.hasText(value)) { - builder.append(SEPARATOR).append(value); - } - } - - public ServiceBeanNameBuilder group(String group) { - this.group = group; - return this; - } - - public ServiceBeanNameBuilder version(String version) { - this.version = version; - return this; - } - - public String build() { - StringBuilder beanNameBuilder = new StringBuilder("ServiceBean"); - // Required - append(beanNameBuilder, interfaceClassName); - // Optional - append(beanNameBuilder, version); - append(beanNameBuilder, group); - // Build - String rawBeanName = beanNameBuilder.toString(); - // Resolve placeholders - return environment.resolvePlaceholders(rawBeanName); - } -} \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilderTest.java similarity index 51% rename from dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java rename to dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilderTest.java index b3616cd58a3..1dcd11391e1 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilderTest.java @@ -16,29 +16,31 @@ */ package org.apache.dubbo.config.spring.beans.factory.annotation; +import static org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationBeanNameBuilderTest.GROUP; +import static org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationBeanNameBuilderTest.VERSION; import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.annotation.Service; import org.apache.dubbo.config.spring.api.DemoService; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; +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; - /** - * {@link ServiceBeanNameBuilder} Test + * {@link AnnotationBeanNameBuilder} Test * - * @see ServiceBeanNameBuilder - * @since 2.6.5 + * @see AnnotationBeanNameBuilder + * @since 2.6.6 */ -@Service(interfaceClass = DemoService.class, group = ServiceBeanNameBuilderTest.GROUP, version = ServiceBeanNameBuilderTest.VERSION, +@Service(interfaceClass = DemoService.class, group = GROUP, version = VERSION, application = "application", module = "module", registry = {"1", "2", "3"}) -public class ServiceBeanNameBuilderTest { +public class AnnotationBeanNameBuilderTest { - @Reference(interfaceClass = DemoService.class, group = "DUBBO", version = "1.0.0", + @Reference(interfaceClass = DemoService.class, group = "DUBBO", version = "${dubbo.version}", application = "application", module = "module", registry = {"1", "2", "3"}) static final Class INTERFACE_CLASS = DemoService.class; @@ -46,30 +48,37 @@ public class ServiceBeanNameBuilderTest { static final String VERSION = "1.0.0"; - static final String BEAN_NAME = "ServiceBean:org.apache.dubbo.config.spring.api.DemoService:1.0.0:DUBBO"; - - private MockEnvironment environment = new MockEnvironment(); + private MockEnvironment environment; - @Test - public void testRequiredAttributes() { - ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(INTERFACE_CLASS, environment); - Assertions.assertEquals("ServiceBean:org.apache.dubbo.config.spring.api.DemoService", builder.build()); + @Before + public void prepare() { + environment = new MockEnvironment(); + environment.setProperty("dubbo.version", "1.0.0"); } @Test public void testServiceAnnotation() { - Service service = AnnotationUtils.getAnnotation(ServiceBeanNameBuilderTest.class, Service.class); - ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, INTERFACE_CLASS, environment); - Assertions.assertEquals(BEAN_NAME, + Service service = AnnotationUtils.getAnnotation(AnnotationBeanNameBuilderTest.class, Service.class); + AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(service, INTERFACE_CLASS); + Assert.assertEquals("providers:dubbo:org.apache.dubbo.config.spring.api.DemoService:1.0.0:DUBBO", + builder.build()); + + builder.environment(environment); + Assert.assertEquals("providers:dubbo:org.apache.dubbo.config.spring.api.DemoService:1.0.0:DUBBO", builder.build()); } @Test public void testReferenceAnnotation() { - Reference reference = AnnotationUtils.getAnnotation(ReflectionUtils.findField(ServiceBeanNameBuilderTest.class, "INTERFACE_CLASS"), Reference.class); - ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, INTERFACE_CLASS, environment); - Assertions.assertEquals(BEAN_NAME, + Reference reference = AnnotationUtils.getAnnotation(ReflectionUtils.findField(AnnotationBeanNameBuilderTest.class, "INTERFACE_CLASS"), Reference.class); + AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(reference, INTERFACE_CLASS); + Assert.assertEquals("consumers:dubbo:org.apache.dubbo.config.spring.api.DemoService:${dubbo.version}:DUBBO", + builder.build()); + + builder.environment(environment); + Assert.assertEquals("consumers:dubbo:org.apache.dubbo.config.spring.api.DemoService:1.0.0:DUBBO", builder.build()); } } + From ca796323def4012e6eda3d43e9e6b12f332eec00 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Thu, 14 Mar 2019 14:42:16 +0800 Subject: [PATCH 13/20] 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/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java index 0a1c33818a3..6f7e8cf445e 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java @@ -316,8 +316,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 438b50b82b0d930d2d22b8b68ad3f9fb5c3244ac Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Thu, 14 Mar 2019 14:57:24 +0800 Subject: [PATCH 14/20] Polish apache/incubator-dubbo#3615 : SpringStatusChecker execute errors on non-XML Spring configuration --- .../spring/status/SpringStatusChecker.java | 195 +++++++++--------- .../status/SpringStatusCheckerTest.java | 13 +- 2 files changed, 113 insertions(+), 95 deletions(-) diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/SpringStatusChecker.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/SpringStatusChecker.java index 9a99ec138fd..63517c6e52a 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/SpringStatusChecker.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/SpringStatusChecker.java @@ -1,94 +1,101 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.dubbo.config.spring.status; - -import org.apache.dubbo.common.extension.Activate; -import org.apache.dubbo.common.logger.Logger; -import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.status.Status; -import org.apache.dubbo.common.status.StatusChecker; -import org.apache.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 org.apache.dubbo.config.spring.status; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.status.Status; +import org.apache.dubbo.common.status.StatusChecker; +import org.apache.dubbo.config.spring.extension.SpringExtensionFactory; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.Lifecycle; +import org.springframework.web.context.support.GenericWebApplicationContext; + +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()) { + // [Issue] SpringStatusChecker execute errors on non-XML Spring configuration + // issue : https://github.com/apache/incubator-dubbo/issues/3615 + if(c instanceof GenericWebApplicationContext) { // ignore GenericXmlApplicationContext + continue; + } + + 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/test/java/org/apache/dubbo/config/spring/status/SpringStatusCheckerTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/status/SpringStatusCheckerTest.java index f3be445103c..e3386e2588d 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/status/SpringStatusCheckerTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/status/SpringStatusCheckerTest.java @@ -20,14 +20,15 @@ import org.apache.dubbo.config.spring.ServiceBean; import org.apache.dubbo.config.spring.extension.SpringExtensionFactory; +import org.junit.Assert; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; - import org.mockito.Mock; import org.mockito.Mockito; import org.springframework.context.ApplicationContext; import org.springframework.context.Lifecycle; +import org.springframework.web.context.support.GenericWebApplicationContext; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @@ -90,4 +91,14 @@ public void testWithoutLifeCycleRunning() { interface ApplicationLifeCycle extends Lifecycle, ApplicationContext { String[] getConfigLocations(); } + + @Test + public void testGenericWebApplicationContext() { + SpringExtensionFactory.clearContexts(); + GenericWebApplicationContext context = new GenericWebApplicationContext(); + SpringExtensionFactory.addApplicationContext(context); + SpringStatusChecker checker = new SpringStatusChecker(); + Status status = checker.check(); + Assert.assertEquals(Status.Level.UNKNOWN, status.getLevel()); + } } From b4f783bc095fc4b6bb1aebb329a4980c84e7753e Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Thu, 14 Mar 2019 15:13:06 +0800 Subject: [PATCH 15/20] Polish apache/incubator-dubbo#3193 : Change the default behavior of @EnableDubboConfig.multiple() --- .../annotation/DubboConfigConfigurationRegistrar.java | 7 ++++--- .../config/spring/context/annotation/EnableDubbo.java | 2 +- .../spring/context/annotation/EnableDubboConfig.java | 6 +++--- .../spring/context/annotation/EnableDubboConfigTest.java | 3 +-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java index cc5f4f8c722..d01dd398ee0 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java @@ -44,10 +44,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); } } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubbo.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubbo.java index 4535f188e4c..706e288597e 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubbo.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/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; } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfig.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfig.java index 47bafa53b54..5a9fe0d595d 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfig.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfig.java @@ -59,7 +59,7 @@ * * @see EnableDubboConfigBinding * @see DubboConfigConfiguration - * @see DubboConfigConfigurationSelector + * @see DubboConfigConfigurationRegistrar * @since 2.5.8 */ @Target({ElementType.TYPE}) @@ -72,9 +72,9 @@ /** * It indicates whether binding to multiple Spring Beans. * - * @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/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java index 5f52a3e0ec0..4945be8a55b 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java @@ -26,7 +26,6 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; - import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.PropertySource; @@ -101,7 +100,7 @@ private static class TestMultipleConfig { } - @EnableDubboConfig + @EnableDubboConfig(multiple = false) @PropertySource("META-INF/config.properties") private static class TestConfig { From 4b5b996863e28a683e3797e6e337999997bd07f7 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Thu, 14 Mar 2019 15:44:06 +0800 Subject: [PATCH 16/20] Polish apache/incubator-dubbo#3189 : Simplify externalized configuration of Dubbo Protocol name --- .../DubboConfigBindingBeanPostProcessor.java | 55 ++++++++++-- .../DubboConfigBindingRegistrar.java | 9 ++ .../config/DubboConfigBeanCustomizer.java | 47 +++++++++++ ...DefaultValueDubboConfigBeanCustomizer.java | 83 +++++++++++++++++++ ...bboConfigBindingBeanPostProcessorTest.java | 56 +++++++------ .../annotation/EnableDubboConfigTest.java | 15 +++- .../test/resources/META-INF/config.properties | 4 + 7 files changed, 237 insertions(+), 32 deletions(-) create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/config/DubboConfigBeanCustomizer.java create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/config/NamePropertyDefaultValueDubboConfigBeanCustomizer.java diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java index 96c4d3885b0..9bfa2606e2d 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java @@ -20,6 +20,7 @@ import org.apache.dubbo.config.AbstractConfig; import org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar; import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfigBinding; +import org.apache.dubbo.config.spring.context.config.DubboConfigBeanCustomizer; import org.apache.dubbo.config.spring.context.properties.DefaultDubboConfigBinder; import org.apache.dubbo.config.spring.context.properties.DubboConfigBinder; @@ -30,8 +31,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 +71,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 +91,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 +156,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 +181,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/org/apache/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java index e797e5585ec..746db48de69 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java @@ -18,6 +18,7 @@ import org.apache.dubbo.config.AbstractConfig; import org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor; +import org.apache.dubbo.config.spring.context.config.NamePropertyDefaultValueDubboConfigBeanCustomizer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -41,6 +42,8 @@ import java.util.Map; import java.util.Set; +import static org.apache.dubbo.config.spring.context.config.NamePropertyDefaultValueDubboConfigBeanCustomizer.BEAN_NAME; +import static org.apache.dubbo.config.spring.util.BeanRegistrar.registerInfrastructureBean; import static org.apache.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties; import static org.apache.dubbo.config.spring.util.PropertySourcesUtils.normalizePrefix; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; @@ -107,6 +110,8 @@ private void registerDubboConfigBeans(String prefix, } + registerDubboConfigBeanCustomizers(registry); + } private void registerDubboConfigBean(String beanName, Class configClass, @@ -149,6 +154,10 @@ private void registerDubboConfigBindingBeanPostProcessor(String prefix, String b } + private void registerDubboConfigBeanCustomizers(BeanDefinitionRegistry registry) { + registerInfrastructureBean(registry, BEAN_NAME, NamePropertyDefaultValueDubboConfigBeanCustomizer.class); + } + @Override public void setEnvironment(Environment environment) { diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/config/DubboConfigBeanCustomizer.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/config/DubboConfigBeanCustomizer.java new file mode 100644 index 00000000000..75bf0dd2eb6 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/config/DubboConfigBeanCustomizer.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.config.spring.context.config; + +import org.apache.dubbo.config.AbstractConfig; +import org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor; +import org.apache.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/org/apache/dubbo/config/spring/context/config/NamePropertyDefaultValueDubboConfigBeanCustomizer.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/config/NamePropertyDefaultValueDubboConfigBeanCustomizer.java new file mode 100644 index 00000000000..fcd053d503c --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/config/NamePropertyDefaultValueDubboConfigBeanCustomizer.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 org.apache.dubbo.config.spring.context.config; + +import org.apache.dubbo.config.AbstractConfig; + +import org.springframework.util.ReflectionUtils; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.Arrays; + +import static org.apache.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 bean name of {@link NamePropertyDefaultValueDubboConfigBeanCustomizer} + * + * @since 2.7.1 + */ + public static final String BEAN_NAME = "namePropertyDefaultValueDubboConfigBeanCustomizer"; + + /** + * 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/org/apache/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java index 7811c7371f1..e679f4f976c 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java @@ -17,50 +17,56 @@ package org.apache.dubbo.config.spring.beans.factory.annotation; import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.spring.context.config.NamePropertyDefaultValueDubboConfigBeanCustomizer; import org.apache.dubbo.config.spring.context.properties.DefaultDubboConfigBinder; -import org.apache.dubbo.config.spring.context.properties.DubboConfigBinder; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.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; +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.context.annotation.Bean; +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); - Assertions.assertEquals("dubbo-demo-application", applicationConfig.getName()); - + 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/org/apache/dubbo/config/spring/context/context/annotation/EnableDubboConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/EnableDubboConfigTest.java index fba874332b3..691f251dac6 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/EnableDubboConfigTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/EnableDubboConfigTest.java @@ -25,11 +25,14 @@ import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfig; +import org.junit.Assert; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.PropertySource; +import java.util.Map; + /** * {@link EnableDubboConfig} Test * @@ -93,15 +96,23 @@ public void testMultiple() { ApplicationConfig applicationBean3 = context.getBean("applicationBean3", ApplicationConfig.class); Assertions.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(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..aa79925d4e7 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 deecedc66c9be7fb914d822a48679c49a8885cd5 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Thu, 14 Mar 2019 22:31:30 +0800 Subject: [PATCH 17/20] Remove useless module --- dubbo-rpc/dubbo-rpc-springmvc/pom.xml | 43 ------------ .../annotation/RestServiceHandlerAdapter.java | 67 ------------------- .../annotation/RestServiceHandlerMapping.java | 47 ------------- ...erviceHandlerMethodReturnValueHandler.java | 54 --------------- dubbo-rpc/pom.xml | 1 - 5 files changed, 212 deletions(-) delete mode 100755 dubbo-rpc/dubbo-rpc-springmvc/pom.xml delete mode 100755 dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerAdapter.java delete mode 100755 dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerMapping.java delete mode 100755 dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerMethodReturnValueHandler.java diff --git a/dubbo-rpc/dubbo-rpc-springmvc/pom.xml b/dubbo-rpc/dubbo-rpc-springmvc/pom.xml deleted file mode 100755 index 400b4e966ea..00000000000 --- a/dubbo-rpc/dubbo-rpc-springmvc/pom.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - dubbo-rpc - com.alibaba - 2.7.0-SNAPSHOT - - 4.0.0 - - dubbo-rpc-springmvc - jar - ${project.artifactId} - The Spring MVC rpc module of dubbo project - - false - - - - - com.alibaba - dubbo-rpc-api - ${project.parent.version} - - - org.springframework - spring-context - - - - javax.servlet - javax.servlet-api - provided - - - - org.springframework - spring-webmvc - - - - \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerAdapter.java b/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerAdapter.java deleted file mode 100755 index 37fde952a98..00000000000 --- a/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerAdapter.java +++ /dev/null @@ -1,67 +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.rpc.protocol.spring.webmvc.method.annotation; - -import com.alibaba.dubbo.rpc.protocol.spring.webmvc.annotation.RestService; -import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.util.ClassUtils; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.method.support.HandlerMethodReturnValueHandler; -import org.springframework.web.servlet.HandlerAdapter; -import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; -import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor; - -import java.util.LinkedList; -import java.util.List; - -/** - * {@link RestService @RestService} {@link HandlerAdapter} - * - * @since 2.7.0 - */ -public class RestServiceHandlerAdapter extends RequestMappingHandlerAdapter { - - protected boolean supportsInternal(HandlerMethod handlerMethod) { - Class beanType = handlerMethod.getBeanType(); - return AnnotatedElementUtils.hasAnnotation(beanType, RestService.class); - } - - @Override - public void afterPropertiesSet() { - - super.afterPropertiesSet(); - - final List allReturnValueHandlers = getReturnValueHandlers(); - - final List restReturnValueHandlers = new LinkedList(); - - for (HandlerMethodReturnValueHandler returnValueHandler : allReturnValueHandlers) { - - if (ClassUtils.isAssignableValue(RequestResponseBodyMethodProcessor.class, returnValueHandler)) { - - RequestResponseBodyMethodProcessor delegate = (RequestResponseBodyMethodProcessor) returnValueHandler; - HandlerMethodReturnValueHandler restReturnValueHandler = new RestServiceHandlerMethodReturnValueHandler(delegate); - restReturnValueHandlers.add(restReturnValueHandler); - } - - } - - setReturnValueHandlers(restReturnValueHandlers); - - } - -} diff --git a/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerMapping.java b/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerMapping.java deleted file mode 100755 index 79f8973b573..00000000000 --- a/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerMapping.java +++ /dev/null @@ -1,47 +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.rpc.protocol.spring.webmvc.method.annotation; - -import com.alibaba.dubbo.rpc.protocol.spring.webmvc.annotation.RestService; -import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.servlet.HandlerMapping; -import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; - -/** - * {@link RestService @RestService} {@link HandlerMapping} implementation that is compatible with - * Spring Web MVC standard {@link RequestMapping @RequestMapping} annotation. - * - * @see RequestMapping - * @see RequestMappingHandlerMapping - * @since 2.7.0 - */ -public class RestServiceHandlerMapping extends RequestMappingHandlerMapping { - - /** - * Default Constructor with highest precedence order. - */ - public RestServiceHandlerMapping() { - setOrder(HIGHEST_PRECEDENCE); - } - - @Override - protected boolean isHandler(Class beanType) { - return AnnotatedElementUtils.hasAnnotation(beanType, RestService.class); - } - -} diff --git a/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerMethodReturnValueHandler.java b/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerMethodReturnValueHandler.java deleted file mode 100755 index df7df609780..00000000000 --- a/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/method/annotation/RestServiceHandlerMethodReturnValueHandler.java +++ /dev/null @@ -1,54 +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.rpc.protocol.spring.webmvc.method.annotation; - -import com.alibaba.dubbo.rpc.protocol.spring.webmvc.annotation.RestService; -import org.springframework.core.MethodParameter; -import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.HandlerMethodReturnValueHandler; -import org.springframework.web.method.support.ModelAndViewContainer; -import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor; - -/** - * {@link RestService @RestService} {@link HandlerMethodReturnValueHandler} implementation - * - * @since 2.7.0 - */ -public class RestServiceHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler { - - private final RequestResponseBodyMethodProcessor processor; - - public RestServiceHandlerMethodReturnValueHandler(RequestResponseBodyMethodProcessor processor) { - this.processor = processor; - } - - @Override - public boolean supportsReturnType(MethodParameter returnType) { - Class serviceClass = returnType.getDeclaringClass(); - return AnnotatedElementUtils.hasAnnotation(serviceClass, RestService.class); - } - - @Override - public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, - NativeWebRequest webRequest) throws Exception { - - processor.handleReturnValue(returnValue, returnType, mavContainer, webRequest); - - } - -} diff --git a/dubbo-rpc/pom.xml b/dubbo-rpc/pom.xml index 098fb3edf9b..03e5b9abf4b 100644 --- a/dubbo-rpc/pom.xml +++ b/dubbo-rpc/pom.xml @@ -40,6 +40,5 @@ dubbo-rpc-memcached dubbo-rpc-redis dubbo-rpc-rest - dubbo-rpc-springmvc From 49f6d41a7a0b3135a01fa1e5716c5317e52dfcc5 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 15 Mar 2019 00:42:04 +0800 Subject: [PATCH 18/20] Polish apache/incubator-dubbo#3582 : nacos support on 2.7 --- .../AbstractCloudNativeRegistryFactory.java | 84 ++++++ .../support/cloud/CloudNativeRegistry.java | 257 ++++++++++++++++++ .../support/cloud/CloudServiceDiscovery.java | 61 +++++ .../support/cloud/CloudServiceRegistry.java | 57 ++++ .../support/cloud/ServiceInstance.java | 50 +++- .../support/cloud/ServiceInstanceFactory.java | 33 ++- dubbo-registry/dubbo-registry-nacos/pom.xml | 148 ++++++++++ .../registry/nacos/NacosCloudService.java | 126 +++++++++ .../registry/nacos/NacosRegistryFactory.java | 132 +++++++++ .../registry/nacos/NacosServiceInstance.java | 64 +++++ .../nacos/NacosServiceInstanceFactory.java | 100 +++++++ .../org.apache.dubbo.registry.RegistryFactory | 1 + .../DemoServiceConsumerBootstrap.java | 54 ++++ .../DemoServiceConsumerXmlBootstrap.java | 41 +++ .../DemoServiceProviderBootstrap.java | 41 +++ .../DemoServiceProviderXmlBootstrap.java | 30 +- .../dubbo/demo/service/DefaultService.java | 38 +-- .../dubbo/demo/service/DemoService.java | 26 +- .../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 + 23 files changed, 1329 insertions(+), 72 deletions(-) create mode 100644 dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/AbstractCloudNativeRegistryFactory.java create mode 100644 dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/CloudNativeRegistry.java create mode 100644 dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/CloudServiceDiscovery.java create mode 100644 dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/CloudServiceRegistry.java rename dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/src/main/java/org/apache/dubbo/test/provider/DefaultDemoService.java => dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/ServiceInstance.java (56%) rename dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/src/main/java/org/apache/dubbo/test/provider/ProviderConfiguration.java => dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/ServiceInstanceFactory.java (54%) create mode 100644 dubbo-registry/dubbo-registry-nacos/pom.xml create mode 100644 dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosCloudService.java create mode 100644 dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistryFactory.java create mode 100644 dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceInstance.java create mode 100644 dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceInstanceFactory.java create mode 100644 dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/org.apache.dubbo.registry.RegistryFactory create mode 100644 dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java create mode 100644 dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java create mode 100644 dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/provider/DemoServiceProviderBootstrap.java rename dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/EnableRestService.java => dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/provider/DemoServiceProviderXmlBootstrap.java (55%) mode change 100755 => 100644 rename dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/RestServiceConfiguration.java => dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/service/DefaultService.java (50%) mode change 100755 => 100644 rename dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/RestService.java => dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/service/DemoService.java (66%) mode change 100755 => 100644 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/org/apache/dubbo/registry/support/cloud/AbstractCloudNativeRegistryFactory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/AbstractCloudNativeRegistryFactory.java new file mode 100644 index 00000000000..b9a14bd169b --- /dev/null +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/AbstractCloudNativeRegistryFactory.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.registry.support.cloud; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.NamedThreadFactory; +import org.apache.dubbo.registry.Registry; +import org.apache.dubbo.registry.support.AbstractRegistryFactory; + +import java.util.concurrent.ScheduledExecutorService; + +import static java.lang.System.getProperty; +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; + +/** + * Abstract {@link CloudNativeRegistry} Factory + * + * @param The subclass of {@link ServiceInstance} + * @since 2.7.1 + */ +public abstract class AbstractCloudNativeRegistryFactory extends AbstractRegistryFactory { + + private static String SERVICES_LOOKUP_SCHEDULER_THREAD_NAME_PREFIX = + getProperty("dubbo.services.lookup.scheduler.thread.name.prefix ", "dubbo-services-lookup-"); + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + private final ScheduledExecutorService servicesLookupScheduler; + + public AbstractCloudNativeRegistryFactory() { + this.servicesLookupScheduler = newSingleThreadScheduledExecutor( + new NamedThreadFactory(SERVICES_LOOKUP_SCHEDULER_THREAD_NAME_PREFIX)); + } + + @Override + protected final Registry createRegistry(URL url) { + return new CloudNativeRegistry(url, + createCloudServiceRegistry(url), + createCloudServiceDiscovery(url), + createServiceInstanceFactory(url), + servicesLookupScheduler + ); + } + + /** + * The subclass implement this method to create {@link CloudServiceRegistry} + * + * @param url The {@link URL} of Dubbo Registry + * @return non-null + */ + protected abstract CloudServiceRegistry createCloudServiceRegistry(URL url); + + /** + * The subclass implement this method to create {@link CloudServiceDiscovery} + * + * @param url The {@link URL} of Dubbo Registry + * @return non-null + */ + protected abstract CloudServiceDiscovery createCloudServiceDiscovery(URL url); + + /** + * The subclass implement this method to create {@link ServiceInstanceFactory} + * + * @param url The {@link URL} of Dubbo Registry + * @return non-null + */ + protected abstract ServiceInstanceFactory createServiceInstanceFactory(URL url); +} diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/CloudNativeRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/CloudNativeRegistry.java new file mode 100644 index 00000000000..bd43f150c7c --- /dev/null +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/CloudNativeRegistry.java @@ -0,0 +1,257 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.registry.support.cloud; + +import org.apache.dubbo.common.Constants; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.utils.UrlUtils; +import org.apache.dubbo.registry.NotifyListener; +import org.apache.dubbo.registry.Registry; +import org.apache.dubbo.registry.support.FailbackRegistry; + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static java.util.Collections.singletonList; +import static org.apache.dubbo.common.Constants.PROVIDER_SIDE; +import static org.apache.dubbo.common.Constants.SIDE_KEY; + +/** + * Dubbo Cloud-Native Service {@link Registry} abstraction + * + * @param The subclass of {@link ServiceInstance} + * @since 2.7.1 + */ +public class CloudNativeRegistry extends FailbackRegistry { + + /** + * The parameter name of {@link #allServicesLookupInterval} + */ + public static final String ALL_SERVICES_LOOKUP_INTERVAL_PARAM_NAME = "dubbo.all.services.lookup.interval"; + + /** + * The parameter name of {@link #registeredServicesLookupInterval} + */ + public static final String REGISTERED_SERVICES_LOOKUP_INTERVAL_PARAM_NAME = "dubbo.registered.services.lookup.interval"; + + /** + * The interval in second of lookup service names(only for Dubbo-OPS) + */ + private final long allServicesLookupInterval; + + private final long registeredServicesLookupInterval; + + private final CloudServiceRegistry cloudServiceRegistry; + + private final CloudServiceDiscovery cloudServiceDiscovery; + + private final ServiceInstanceFactory serviceInstanceFactory; + + private final ScheduledExecutorService servicesLookupScheduler; + + public CloudNativeRegistry(URL url, + CloudServiceRegistry cloudServiceRegistry, + CloudServiceDiscovery cloudServiceDiscovery, + ServiceInstanceFactory serviceInstanceFactory, + ScheduledExecutorService servicesLookupScheduler) { + super(url); + this.allServicesLookupInterval = url.getParameter(ALL_SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 30L); + this.registeredServicesLookupInterval = url.getParameter(REGISTERED_SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 300L); + this.cloudServiceRegistry = cloudServiceRegistry; + this.cloudServiceDiscovery = cloudServiceDiscovery; + this.serviceInstanceFactory = serviceInstanceFactory; + this.servicesLookupScheduler = servicesLookupScheduler; + } + + protected boolean shouldRegister(S serviceInstance) { + Map metadata = serviceInstance.getMetadata(); + String side = metadata.get(SIDE_KEY); + return PROVIDER_SIDE.equals(side); // Only register the Provider. + } + + @Override + public void doRegister(URL url) { + S serviceInstance = serviceInstanceFactory.create(url); + if (shouldRegister(serviceInstance)) { + cloudServiceRegistry.register(serviceInstance); + } + } + + @Override + public void doUnregister(URL url) { + S serviceInstance = serviceInstanceFactory.create(url); + if (shouldRegister(serviceInstance)) { + cloudServiceRegistry.deregister(serviceInstance); + } + } + + @Override + public void doSubscribe(URL url, NotifyListener listener) { + List serviceNames = getServiceNames(url, listener); + doSubscribe(url, listener, serviceNames); + this.servicesLookupScheduler.scheduleAtFixedRate(() -> { + doSubscribe(url, listener, serviceNames); + }, registeredServicesLookupInterval, registeredServicesLookupInterval, TimeUnit.SECONDS); + } + + @Override + public void doUnsubscribe(URL url, NotifyListener listener) { + if (isAdminProtocol(url)) { + shutdownServiceNamesLookup(); + } + } + + private void shutdownServiceNamesLookup() { + if (servicesLookupScheduler != null) { + servicesLookupScheduler.shutdown(); + } + } + + /** + * Get all service names + * + * @return non-null {@link List} + */ + protected List getAllServiceNames() { + return cloudServiceDiscovery.getServices(); + } + + private void doSubscribe(final URL url, final NotifyListener listener, final List serviceNames) { + for (String serviceName : serviceNames) { + List serviceInstances = cloudServiceDiscovery.getServiceInstances(serviceName); + notifySubscriber(url, listener, serviceInstances); + } + } + + /** + * Get the service names from the specified {@link URL url} + * + * @param url {@link URL} + * @param listener {@link NotifyListener} + * @return non-null + */ + private List getServiceNames(URL url, NotifyListener listener) { + if (isAdminProtocol(url)) { + initAllServicesLookupScheduler(url, listener); + return getServiceNamesForOps(url); + } else { + return singletonList(serviceInstanceFactory.createServiceName(url)); + } + } + + /** + * Get the service names for Dubbo OPS + * + * @param url {@link URL} + * @return non-null + */ + private List getServiceNamesForOps(URL url) { + List serviceNames = getAllServiceNames(); + filterServiceNames(serviceNames); + return serviceNames; + } + + + private boolean isAdminProtocol(URL url) { + return Constants.ADMIN_PROTOCOL.equals(url.getProtocol()); + } + + private void filter(Collection collection, Predicate predicate) { + Iterator iterator = collection.iterator(); + while (iterator.hasNext()) { + T data = iterator.next(); + if (!predicate.test(data)) { // remove if not accept + iterator.remove(); + } + } + } + + private void initAllServicesLookupScheduler(final URL url, final NotifyListener listener) { + servicesLookupScheduler.scheduleAtFixedRate(() -> { + List serviceNames = getAllServiceNames(); + filterServiceNames(serviceNames); + doSubscribe(url, listener, serviceNames); + }, allServicesLookupInterval, allServicesLookupInterval, TimeUnit.SECONDS); + } + + private void filterServiceNames(List serviceNames) { + filter(serviceNames, cloudServiceDiscovery::supports); + } + + private void doSubscribe(final URL url, final NotifyListener listener, final Set serviceNames) { + Collection serviceInstances = serviceNames.stream() + .map(cloudServiceDiscovery::getServiceInstances) + .flatMap(v -> v.stream()) + .collect(Collectors.toList()); + notifySubscriber(url, listener, serviceInstances); + } + + /** + * Notify the Healthy {@link S 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, cloudServiceRegistry::isHealthy); + } + + private List buildURLs(URL consumerURL, Collection serviceInstances) { + if (serviceInstances.isEmpty()) { + return Collections.emptyList(); + } + List urls = new LinkedList(); + for (S serviceInstance : serviceInstances) { + URL url = buildURL(serviceInstance); + if (UrlUtils.isMatch(consumerURL, url)) { + urls.add(url); + } + } + return urls; + } + + private URL buildURL(S serviceInstance) { + URL url = new URL(serviceInstance.getMetadata().get(Constants.PROTOCOL_KEY), + serviceInstance.getHost(), serviceInstance.getPort(), + serviceInstance.getMetadata()); + return url; + } + + @Override + public boolean isAvailable() { + return cloudServiceRegistry.isAvailable(); + } +} diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/CloudServiceDiscovery.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/CloudServiceDiscovery.java new file mode 100644 index 00000000000..ff8907abb76 --- /dev/null +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/CloudServiceDiscovery.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.registry.support.cloud; + +import java.util.List; + +/** + * Cloud {@link ServiceInstance Service} Discovery + * + * @param The subclass of {@link ServiceInstance} + * @since 2.7.1 + */ +public interface CloudServiceDiscovery { + + /** + * The total number of all services. + * + * @return must be equal or more than 0 + */ + default long getTotalServices() { + return getServices().size(); + } + + /** + * Get all service names + * + * @return non-null read-only {@link List} + */ + List getServices(); + + + /** + * Get all service instances by the specified name + * + * @param serviceName the service name + * @return non-null read-only {@link List} + */ + List getServiceInstances(String serviceName); + + /** + * Supports the specified name of Cloud Service or not + * + * @param serviceName the specified service name + * @return if supports, return true, or false + */ + boolean supports(String serviceName); +} diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/CloudServiceRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/CloudServiceRegistry.java new file mode 100644 index 00000000000..eb0eaf032f5 --- /dev/null +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/CloudServiceRegistry.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.registry.support.cloud; + +/** + * Cloud {@link ServiceInstance Service} Registry + * + * @param The subclass of {@link ServiceInstance} + * @since 2.7.1 + */ +public interface CloudServiceRegistry extends AutoCloseable { + + /** + * Registers the {@link ServiceInstance}. + * + * @param serviceInstance The {@link ServiceInstance} + */ + void register(S serviceInstance); + + /** + * Deregisters the {@link ServiceInstance} + * + * @param serviceInstance The {@link ServiceInstance} + */ + void deregister(S serviceInstance); + + + /** + * Test the specified {@link ServiceInstance} is healthy or not + * + * @param serviceInstance The {@link ServiceInstance} + * @return true if the specified {@link ServiceInstance} is healthy + */ + boolean isHealthy(S serviceInstance); + + /** + * Is available or not + * + * @return true if current {@link CloudServiceRegistry} is available + */ + boolean isAvailable(); + +} diff --git a/dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/src/main/java/org/apache/dubbo/test/provider/DefaultDemoService.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/ServiceInstance.java similarity index 56% rename from dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/src/main/java/org/apache/dubbo/test/provider/DefaultDemoService.java rename to dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/ServiceInstance.java index 7c747717ef9..fae97bc6374 100644 --- a/dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/src/main/java/org/apache/dubbo/test/provider/DefaultDemoService.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/ServiceInstance.java @@ -14,27 +14,47 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.test.provider; +package org.apache.dubbo.registry.support.cloud; -import org.apache.dubbo.config.annotation.Service; -import org.apache.dubbo.demo.DemoService; +import java.util.Map; /** - * Default {@link DemoService} implementation + * The Service Instance * - * @since 2.5.8 + * @since 2.7.1 */ -@Service( - version = "2.5.8", - application = "dubbo-annotation-provider", - protocol = "dubbo", - registry = "my-registry" -) -public class DefaultDemoService implements DemoService { +public interface ServiceInstance { - @Override - public String sayHello(String name) { - return "DefaultDemoService - sayHell() : " + name; + /** + * @return The service name + */ + String getServiceName(); + + /** + * @return The Host + */ + String getHost(); + + /** + * @return The service port + */ + int getPort(); + + /** + * @return The read-only metadata + */ + Map getMetadata(); + + /** + * @return The scheme of the service instance. + */ + default String getScheme() { + return null; } + @Override + boolean equals(Object o); + + @Override + int hashCode(); } diff --git a/dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/src/main/java/org/apache/dubbo/test/provider/ProviderConfiguration.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/ServiceInstanceFactory.java similarity index 54% rename from dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/src/main/java/org/apache/dubbo/test/provider/ProviderConfiguration.java rename to dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/ServiceInstanceFactory.java index d959e544516..7f8d21ebc92 100644 --- a/dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/src/main/java/org/apache/dubbo/test/provider/ProviderConfiguration.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/ServiceInstanceFactory.java @@ -14,20 +14,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.test.provider; +package org.apache.dubbo.registry.support.cloud; -import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan; - -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportResource; +import org.apache.dubbo.common.URL; /** - * Provider {@Link Configuration} + * {@link ServiceInstance} Factory to create a instance of {@link ServiceInstance} * - * @since 2.5.8 + * @param The subclass of {@link ServiceInstance} + * @since 2.7.1 */ -@Configuration -@ImportResource("META-INF/spring/dubbo-provider.xml") -@DubboComponentScan -public class ProviderConfiguration { +public interface ServiceInstanceFactory { + + /** + * Creates a instance of {@link S} + * + * @param url The Dubbo's {@link URL} + * @return a instance of {@link S}, if null, it indicates the registration will not be executed. + */ + S create(URL url); + + /** + * Creates the Service Name + * + * @param url The Dubbo's {@link URL} + * @return non-null + */ + String createServiceName(URL url); } diff --git a/dubbo-registry/dubbo-registry-nacos/pom.xml b/dubbo-registry/dubbo-registry-nacos/pom.xml new file mode 100644 index 00000000000..2abf8b07538 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/pom.xml @@ -0,0 +1,148 @@ + + + + org.apache.dubbo + dubbo-registry + 2.7.1-SNAPSHOT + ../pom.xml + + 4.0.0 + + org.apache.dubbo + dubbo-registry-nacos + ${project.artifactId} + The Nacos registry module of Dubbo project + + + UTF-8 + UTF-8 + 0.9.0 + + + + + + org.apache.dubbo + dubbo-registry-api + ${project.version} + true + + + + org.apache.dubbo + dubbo-common + ${project.version} + true + + + + com.alibaba.nacos + nacos-client + ${nacos.version} + true + + + + + org.apache.dubbo + dubbo-config-api + ${project.version} + test + + + + org.apache.dubbo + dubbo-serialization-hessian2 + ${project.version} + test + + + + org.apache.dubbo + dubbo-config-spring + ${project.version} + test + + + + org.apache.dubbo + dubbo-rpc-dubbo + ${project.version} + test + + + + org.apache.dubbo + dubbo-remoting-netty4 + ${project.version} + test + + + + ch.qos.logback + logback-classic + 1.2.3 + test + + + + + org.apache.dubbo + 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/org/apache/dubbo/registry/nacos/NacosCloudService.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosCloudService.java new file mode 100644 index 00000000000..d3074974b7b --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosCloudService.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.registry.nacos; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.NamingService; + +import org.apache.dubbo.registry.support.cloud.CloudServiceDiscovery; +import org.apache.dubbo.registry.support.cloud.CloudServiceRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.stream.Collectors; + +import static org.apache.commons.lang3.StringUtils.startsWithIgnoreCase; +import static org.apache.dubbo.common.Constants.CONSUMERS_CATEGORY; +import static org.apache.dubbo.common.Constants.PROVIDERS_CATEGORY; + +/** + * Nacos Cloud Service implements {@link CloudServiceRegistry} and {@link CloudServiceDiscovery} + */ +class NacosCloudService implements CloudServiceRegistry, CloudServiceDiscovery { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final NamingService namingService; + + public NacosCloudService(NamingService namingService) { + this.namingService = namingService; + } + + @Override + public List getServices() { + return execute(namingService -> + namingService.getServicesOfServer(0, Integer.MAX_VALUE).getData() + ); + } + + @Override + public List getServiceInstances(String serviceName) { + return execute(namingService -> + namingService.selectInstances(serviceName, true) + .stream().map(NacosServiceInstance::new) + .collect(Collectors.toList()) + ); + } + + @Override + public boolean supports(String serviceName) { + return startsWithIgnoreCase(serviceName, PROVIDERS_CATEGORY) || + startsWithIgnoreCase(serviceName, CONSUMERS_CATEGORY); + } + + @Override + public void register(NacosServiceInstance serviceInstance) { + execute(namingService -> { + namingService.registerInstance(serviceInstance.getServiceName(), serviceInstance.getSource()); + return null; + }); + } + + @Override + public void deregister(NacosServiceInstance serviceInstance) { + execute(namingService -> { + namingService.deregisterInstance(serviceInstance.getServiceName(), + serviceInstance.getHost(), serviceInstance.getPort()); + return null; + }); + } + + @Override + public boolean isHealthy(NacosServiceInstance serviceInstance) { + return serviceInstance.getSource().isHealthy(); + } + + @Override + public boolean isAvailable() { + return "UP".equals(namingService.getServerStatus()); + } + + @Override + public void close() throws Exception { + // DO NOTHING + } + + private T execute(NamingServiceFunction function) { + try { + return function.apply(namingService); + } catch (NacosException e) { + if (logger.isErrorEnabled()) { + logger.error(e.getErrMsg(), e); + } + throw new RuntimeException(e); + } + } + + /** + * {@link NamingService} Function + */ + interface NamingServiceFunction { + + /** + * Callback + * + * @param namingService {@link NamingService} + * @throws NacosException + */ + T apply(NamingService namingService) throws NacosException; + + } +} diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistryFactory.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistryFactory.java new file mode 100644 index 00000000000..02e0d61434a --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistryFactory.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.registry.nacos; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.registry.RegistryFactory; +import org.apache.dubbo.registry.support.cloud.AbstractCloudNativeRegistryFactory; +import org.apache.dubbo.registry.support.cloud.CloudServiceDiscovery; +import org.apache.dubbo.registry.support.cloud.CloudServiceRegistry; +import org.apache.dubbo.registry.support.cloud.ServiceInstanceFactory; + +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.HashMap; +import java.util.Map; +import java.util.Properties; + +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; +import static org.apache.dubbo.common.Constants.BACKUP_KEY; + +/** + * Nacos {@link RegistryFactory} + * + * @since 2.6.6 + */ +public class NacosRegistryFactory extends AbstractCloudNativeRegistryFactory { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private Map nacosCloudServicesCache = new HashMap<>(); + + 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); + } + } + + private NacosCloudService createNacosCloudService(URL url) { + nacosCloudServicesCache.computeIfAbsent(url, u -> + new NacosCloudService(buildNamingService(u)) + ); + return nacosCloudServicesCache.get(url); + } + + @Override + protected CloudServiceRegistry createCloudServiceRegistry(URL url) { + return createNacosCloudService(url); + } + + @Override + protected CloudServiceDiscovery createCloudServiceDiscovery(URL url) { + return createNacosCloudService(url); + } + + @Override + protected ServiceInstanceFactory createServiceInstanceFactory(URL url) { + return new NacosServiceInstanceFactory(); + } +} diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceInstance.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceInstance.java new file mode 100644 index 00000000000..775df9aadab --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceInstance.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.registry.nacos; + +import org.apache.dubbo.registry.support.cloud.ServiceInstance; + +import com.alibaba.nacos.api.naming.pojo.Instance; + +import java.util.Map; + +/** + * Nacos {@link ServiceInstance} + */ +public class NacosServiceInstance implements ServiceInstance { + + private final Instance source; + + public NacosServiceInstance(Instance instance) { + this.source = instance; + } + + @Override + public String getServiceName() { + return source.getServiceName(); + } + + @Override + public String getHost() { + return source.getIp(); + } + + @Override + public int getPort() { + return source.getPort(); + } + + @Override + public Map getMetadata() { + return source.getMetadata(); + } + + @Override + public String getScheme() { + return "nacos"; + } + + public Instance getSource() { + return source; + } +} diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceInstanceFactory.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceInstanceFactory.java new file mode 100644 index 00000000000..73850c610a0 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceInstanceFactory.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.registry.nacos; + +import com.alibaba.nacos.api.naming.pojo.Instance; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.registry.support.cloud.ServiceInstanceFactory; + +import java.util.LinkedHashMap; +import java.util.Objects; + +import static java.lang.System.getProperty; +import static org.apache.dubbo.common.Constants.CATEGORY_KEY; +import static org.apache.dubbo.common.Constants.CONSUMERS_CATEGORY; +import static org.apache.dubbo.common.Constants.DEFAULT_CATEGORY; +import static org.apache.dubbo.common.Constants.GROUP_KEY; +import static org.apache.dubbo.common.Constants.INTERFACE_KEY; +import static org.apache.dubbo.common.Constants.PROTOCOL_KEY; +import static org.apache.dubbo.common.Constants.PROVIDERS_CATEGORY; +import static org.apache.dubbo.common.Constants.VERSION_KEY; + +/** + * Nacos {@link ServiceInstanceFactory} + * + * @since 2.7.1 + */ +public class NacosServiceInstanceFactory implements ServiceInstanceFactory { + + /** + * The separator for service name + */ + private static final String SERVICE_NAME_SEPARATOR = getProperty("dubbo.service.name.separator", ":"); + + @Override + public NacosServiceInstance create(URL url) { + Instance instance = createInstance(url); + return new NacosServiceInstance(instance); + } + + private Instance createInstance(URL url) { + // Append default category if absent + String category = url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY); + URL newURL = url.addParameter(CATEGORY_KEY, category); + newURL = newURL.addParameter(PROTOCOL_KEY, url.getProtocol()); + String ip = url.getHost(); + int port = url.getPort(); + String serviceName = createServiceName(url); + Instance instance = new Instance(); + instance.setServiceName(serviceName); + instance.setIp(ip); + instance.setPort(port); + instance.setMetadata(new LinkedHashMap<>(newURL.getParameters())); + return instance; + } + + @Override + public String createServiceName(URL url) { + String category = url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY); + if (!Objects.equals(category, PROVIDERS_CATEGORY) && !Objects.equals(category, CONSUMERS_CATEGORY)) { + category = PROVIDERS_CATEGORY; + } + return createServiceName(url, category); + } + + private static String createServiceName(URL url, String category) { + StringBuilder serviceNameBuilder = new StringBuilder(category); + appendIfPresent(serviceNameBuilder, url, INTERFACE_KEY); + appendIfPresent(serviceNameBuilder, url, VERSION_KEY); + appendIfPresent(serviceNameBuilder, url, GROUP_KEY); + return serviceNameBuilder.toString(); + } + + private static void appendIfPresent(StringBuilder target, URL url, + String parameterName) { + String parameterValue = url.getParameter(parameterName); + appendIfPresent(target, parameterValue); + } + + 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/src/main/resources/META-INF/dubbo/org.apache.dubbo.registry.RegistryFactory b/dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/org.apache.dubbo.registry.RegistryFactory new file mode 100644 index 00000000000..bb754674978 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/org.apache.dubbo.registry.RegistryFactory @@ -0,0 +1 @@ +nacos=org.apache.dubbo.registry.nacos.NacosRegistryFactory \ No newline at end of file diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java new file mode 100644 index 00000000000..cf2754a1ddf --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.demo.consumer; + +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; +import org.apache.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}", protocol = "dubbo") + private DemoService demoService; + + @PostConstruct + public void init() throws InterruptedException { + for (int j = 0; j < 10; j++) { + System.out.println(demoService.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/org/apache/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java new file mode 100644 index 00000000000..d2a7a7bd9fe --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.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 org.apache.dubbo.demo.consumer; + +import org.apache.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/org/apache/dubbo/demo/provider/DemoServiceProviderBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/provider/DemoServiceProviderBootstrap.java new file mode 100644 index 00000000000..c1d2ec4f0f5 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/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 org.apache.dubbo.demo.provider; + +import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; +import org.apache.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 = "org.apache.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-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/EnableRestService.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/provider/DemoServiceProviderXmlBootstrap.java old mode 100755 new mode 100644 similarity index 55% rename from dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/EnableRestService.java rename to dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/provider/DemoServiceProviderXmlBootstrap.java index efd8aa9385c..0a37f3fabe9 --- a/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/EnableRestService.java +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/provider/DemoServiceProviderXmlBootstrap.java @@ -14,24 +14,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alibaba.dubbo.rpc.protocol.spring.webmvc.annotation; +package org.apache.dubbo.demo.provider; -import org.springframework.context.annotation.Import; +import org.apache.dubbo.demo.service.DemoService; -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 org.springframework.context.support.ClassPathXmlApplicationContext; + +import java.io.IOException; /** - * Enable {@link RestService Rest Service} - * - * @since 2.7.0 + * {@link DemoService} provider demo XML bootstrap */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Import(RestServiceConfiguration.class) -public @interface EnableRestService { +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-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/RestServiceConfiguration.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/service/DefaultService.java old mode 100755 new mode 100644 similarity index 50% rename from dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/RestServiceConfiguration.java rename to dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/service/DefaultService.java index 2774ccd3267..a7c87d32afd --- a/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/RestServiceConfiguration.java +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/service/DefaultService.java @@ -14,30 +14,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alibaba.dubbo.rpc.protocol.spring.webmvc.annotation; +package org.apache.dubbo.demo.service; + +import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.rpc.RpcContext; +import org.springframework.beans.factory.annotation.Value; -import com.alibaba.dubbo.rpc.protocol.spring.webmvc.method.annotation.RestServiceHandlerAdapter; -import com.alibaba.dubbo.rpc.protocol.spring.webmvc.method.annotation.RestServiceHandlerMapping; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; /** - * {@link RestService} + * Default {@link DemoService} * - * @since 2.7.0 + * @since 2.6.5 */ -@Configuration -public class RestServiceConfiguration { +@Service(version = "${demo.service.version}") +public class DefaultService implements DemoService { - @Bean - public RestServiceHandlerMapping restServiceHandlerMapping() { - return new RestServiceHandlerMapping(); - } + @Value("${demo.service.name}") + private String serviceName; - @Bean - public RestServiceHandlerAdapter restServiceHandlerAdapter(){ - return new RestServiceHandlerAdapter(); + 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-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/RestService.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/service/DemoService.java old mode 100755 new mode 100644 similarity index 66% rename from dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/RestService.java rename to dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/service/DemoService.java index 62aa81c5eec..0c808779311 --- a/dubbo-rpc/dubbo-rpc-springmvc/src/main/java/com/alibaba/dubbo/rpc/protocol/spring/webmvc/annotation/RestService.java +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/service/DemoService.java @@ -14,21 +14,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alibaba.dubbo.rpc.protocol.spring.webmvc.annotation; +package org.apache.dubbo.demo.service; -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 javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; /** - * Rest Service Annotation + * DemoService * - * @since 2.7.0 + * @since 2.6.5 */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface RestService { -} +@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/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..d4ad9324816 --- /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..adf937dd544 --- /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..a52a00b2f86 --- /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 33a329bb0fd..ea09685010a 100644 --- a/dubbo-registry/pom.xml +++ b/dubbo-registry/pom.xml @@ -36,5 +36,6 @@ dubbo-registry-redis dubbo-registry-consul dubbo-registry-etcd3 + dubbo-registry-nacos From 7b9f76d73c481085563203ba826b5771cfd3f1ce Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 15 Mar 2019 10:22:09 +0800 Subject: [PATCH 19/20] Polish apache/incubator-dubbo#3582 : Add Path --- .../support/cloud/CloudNativeRegistry.java | 22 +++++++++---------- .../nacos/NacosServiceInstanceFactory.java | 2 ++ .../DemoServiceConsumerBootstrap.java | 6 ++++- .../test/resources/provider-config.properties | 4 ++-- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/CloudNativeRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/CloudNativeRegistry.java index bd43f150c7c..7caefea8aab 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/CloudNativeRegistry.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/cloud/CloudNativeRegistry.java @@ -37,6 +37,8 @@ import java.util.stream.Collectors; import static java.util.Collections.singletonList; +import static org.apache.dubbo.common.Constants.PATH_KEY; +import static org.apache.dubbo.common.Constants.PROTOCOL_KEY; import static org.apache.dubbo.common.Constants.PROVIDER_SIDE; import static org.apache.dubbo.common.Constants.SIDE_KEY; @@ -140,13 +142,6 @@ protected List getAllServiceNames() { return cloudServiceDiscovery.getServices(); } - private void doSubscribe(final URL url, final NotifyListener listener, final List serviceNames) { - for (String serviceName : serviceNames) { - List serviceInstances = cloudServiceDiscovery.getServiceInstances(serviceName); - notifySubscriber(url, listener, serviceInstances); - } - } - /** * Get the service names from the specified {@link URL url} * @@ -202,7 +197,7 @@ private void filterServiceNames(List serviceNames) { filter(serviceNames, cloudServiceDiscovery::supports); } - private void doSubscribe(final URL url, final NotifyListener listener, final Set serviceNames) { + private void doSubscribe(final URL url, final NotifyListener listener, final Collection serviceNames) { Collection serviceInstances = serviceNames.stream() .map(cloudServiceDiscovery::getServiceInstances) .flatMap(v -> v.stream()) @@ -237,15 +232,20 @@ private List buildURLs(URL consumerURL, Collection serviceInstances) { for (S serviceInstance : serviceInstances) { URL url = buildURL(serviceInstance); if (UrlUtils.isMatch(consumerURL, url)) { - urls.add(url); + urls.add(url.setPath(consumerURL.getPath())); } } return urls; } private URL buildURL(S serviceInstance) { - URL url = new URL(serviceInstance.getMetadata().get(Constants.PROTOCOL_KEY), - serviceInstance.getHost(), serviceInstance.getPort(), + Map metadata = serviceInstance.getMetadata(); + String path = metadata.get(PATH_KEY); + String protocol = metadata.get(PROTOCOL_KEY); + URL url = new URL(protocol, + serviceInstance.getHost(), + serviceInstance.getPort(), + path, serviceInstance.getMetadata()); return url; } diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceInstanceFactory.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceInstanceFactory.java index 73850c610a0..fba511b39d2 100644 --- a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceInstanceFactory.java +++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceInstanceFactory.java @@ -31,6 +31,7 @@ import static org.apache.dubbo.common.Constants.DEFAULT_CATEGORY; import static org.apache.dubbo.common.Constants.GROUP_KEY; import static org.apache.dubbo.common.Constants.INTERFACE_KEY; +import static org.apache.dubbo.common.Constants.PATH_KEY; import static org.apache.dubbo.common.Constants.PROTOCOL_KEY; import static org.apache.dubbo.common.Constants.PROVIDERS_CATEGORY; import static org.apache.dubbo.common.Constants.VERSION_KEY; @@ -58,6 +59,7 @@ private Instance createInstance(URL url) { String category = url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY); URL newURL = url.addParameter(CATEGORY_KEY, category); newURL = newURL.addParameter(PROTOCOL_KEY, url.getProtocol()); + newURL = newURL.addParameter(PATH_KEY, url.getPath()); String ip = url.getHost(); int port = url.getPort(); String serviceName = createServiceName(url); diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java index cf2754a1ddf..3e0caf20275 100644 --- a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java @@ -33,13 +33,17 @@ @PropertySource(value = "classpath:/consumer-config.properties") public class DemoServiceConsumerBootstrap { - @Reference(version = "${demo.service.version}", protocol = "dubbo") + @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)); } 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 index a52a00b2f86..e2dd335b0ed 100644 --- a/dubbo-registry/dubbo-registry-nacos/src/test/resources/provider-config.properties +++ b/dubbo-registry/dubbo-registry-nacos/src/test/resources/provider-config.properties @@ -7,8 +7,8 @@ dubbo.registry.address=127.0.0.1:8848 ### Dubbo Protocol using random port dubbo.protocols.dubbo.port=-1 ### REST protocol -#dubbo.protocols.rest.port=9090 -#dubbo.protocols.rest.server=netty +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 From c1b942dc9a4f330ecb809c62fb832b9d2b9ecc78 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 15 Mar 2019 10:44:00 +0800 Subject: [PATCH 20/20] Polish apache/incubator-dubbo#3582 : Add Enabled logic --- .../org/apache/dubbo/registry/nacos/NacosCloudService.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosCloudService.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosCloudService.java index d3074974b7b..2d8d4ed11a6 100644 --- a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosCloudService.java +++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosCloudService.java @@ -18,6 +18,7 @@ import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.pojo.Instance; import org.apache.dubbo.registry.support.cloud.CloudServiceDiscovery; import org.apache.dubbo.registry.support.cloud.CloudServiceRegistry; @@ -55,7 +56,9 @@ public List getServices() { public List getServiceInstances(String serviceName) { return execute(namingService -> namingService.selectInstances(serviceName, true) - .stream().map(NacosServiceInstance::new) + .stream() + .filter(Instance::isEnabled) + .map(NacosServiceInstance::new) .collect(Collectors.toList()) ); }