diff --git a/dubbo-compatible/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/CompatibleReferenceBeanBuilder.java b/dubbo-compatible/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/CompatibleReferenceBeanBuilder.java index e9276a96cfe..1883f791dcf 100644 --- a/dubbo-compatible/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/CompatibleReferenceBeanBuilder.java +++ b/dubbo-compatible/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/CompatibleReferenceBeanBuilder.java @@ -16,23 +16,24 @@ */ package org.apache.dubbo.config.spring.beans.factory.annotation; -import org.apache.dubbo.config.ConsumerConfig; -import org.apache.dubbo.config.spring.ReferenceBean; -import org.apache.dubbo.config.spring.convert.converter.StringArrayToMapConverter; -import org.apache.dubbo.config.spring.convert.converter.StringArrayToStringConverter; - import com.alibaba.dubbo.config.annotation.Reference; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.config.ConsumerConfig; +import org.apache.dubbo.config.spring.ReferenceBean; +import org.springframework.beans.propertyeditors.StringTrimmerEditor; import org.springframework.context.ApplicationContext; -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springframework.validation.DataBinder; +import java.beans.PropertyEditorSupport; +import java.util.Map; + import static org.apache.dubbo.config.spring.util.BeanFactoryUtils.getOptionalBean; import static org.apache.dubbo.config.spring.util.ObjectUtils.of; +import static org.springframework.util.StringUtils.commaDelimitedListToStringArray; /** * {@link ReferenceBean} Builder @@ -43,6 +44,9 @@ class CompatibleReferenceBeanBuilder extends AbstractAnnotationConfigBeanBuilder { + // Ignore those fields + static final String[] IGNORE_FIELD_NAMES = of("application", "module", "consumer", "monitor", "registry"); + private CompatibleReferenceBeanBuilder(Reference annotation, ClassLoader classLoader, ApplicationContext applicationContext) { super(annotation, classLoader, applicationContext); } @@ -96,20 +100,30 @@ protected ReferenceBean doBuild() { protected void preConfigureBean(Reference reference, ReferenceBean referenceBean) { Assert.notNull(interfaceClass, "The interface class must set first!"); DataBinder dataBinder = new DataBinder(referenceBean); - // Set ConversionService - dataBinder.setConversionService(getConversionService()); - // Ignore those fields - String[] ignoreAttributeNames = of("application", "module", "consumer", "monitor", "registry"); -// dataBinder.setDisallowedFields(ignoreAttributeNames); + // Register CustomEditors for special fields + dataBinder.registerCustomEditor(String.class, "filter", new StringTrimmerEditor(true)); + dataBinder.registerCustomEditor(String.class, "listener", new StringTrimmerEditor(true)); + dataBinder.registerCustomEditor(Map.class, "parameters", new PropertyEditorSupport() { + + public void setAsText(String text) throws java.lang.IllegalArgumentException { + // Trim all whitespace + String content = StringUtils.trimAllWhitespace(text); + if (!StringUtils.hasText(content)) { // No content , ignore directly + return; + } + // replace "=" to "," + content = StringUtils.replace(content, "=", ","); + // replace ":" to "," + content = StringUtils.replace(content, ":", ","); + // String[] to Map + Map parameters = CollectionUtils.toStringMap(commaDelimitedListToStringArray(content)); + setValue(parameters); + } + }); + // Bind annotation attributes - dataBinder.bind(new AnnotationPropertyValuesAdapter(reference, applicationContext.getEnvironment(), ignoreAttributeNames)); - } + dataBinder.bind(new AnnotationPropertyValuesAdapter(reference, applicationContext.getEnvironment(), IGNORE_FIELD_NAMES)); - private ConversionService getConversionService() { - DefaultConversionService conversionService = new DefaultConversionService(); - conversionService.addConverter(new StringArrayToStringConverter()); - conversionService.addConverter(new StringArrayToMapConverter()); - return conversionService; } @@ -147,7 +161,7 @@ protected void postConfigureBean(Reference annotation, ReferenceBean bean) throw } public static CompatibleReferenceBeanBuilder create(Reference annotation, ClassLoader classLoader, - ApplicationContext applicationContext) { + ApplicationContext applicationContext) { return new CompatibleReferenceBeanBuilder(annotation, classLoader, applicationContext); } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java index 63bbea99cd4..fca9a2aef3e 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java @@ -1,309 +1,354 @@ -/* - * 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; - -import org.apache.dubbo.common.Constants; -import org.apache.dubbo.common.utils.StringUtils; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ConfigCenterConfig; -import org.apache.dubbo.config.MetadataReportConfig; -import org.apache.dubbo.config.ModuleConfig; -import org.apache.dubbo.config.MonitorConfig; -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.ProviderConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ServiceConfig; -import org.apache.dubbo.config.annotation.Service; -import org.apache.dubbo.config.spring.extension.SpringExtensionFactory; - -import org.springframework.aop.support.AopUtils; -import org.springframework.beans.factory.BeanFactoryUtils; -import org.springframework.beans.factory.BeanNameAware; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextRefreshedEvent; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import static org.apache.dubbo.config.spring.util.BeanFactoryUtils.addApplicationListener; - -/** - * ServiceFactoryBean - * - * @export - */ -public class ServiceBean extends ServiceConfig implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware { - - private static final long serialVersionUID = 213195494150089726L; - - private final transient Service service; - - private transient ApplicationContext applicationContext; - - private transient String beanName; - - private transient boolean supportedApplicationListener; - - public ServiceBean() { - super(); - this.service = null; - } - - public ServiceBean(Service service) { - super(service); - this.service = service; - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) { - this.applicationContext = applicationContext; - SpringExtensionFactory.addApplicationContext(applicationContext); - supportedApplicationListener = addApplicationListener(applicationContext, this); - } - - @Override - public void setBeanName(String name) { - this.beanName = name; - } - - /** - * Gets associated {@link Service} - * - * @return associated {@link Service} - */ - public Service getService() { - return service; - } - - @Override - public void onApplicationEvent(ContextRefreshedEvent event) { - if (!isExported() && !isUnexported()) { - if (logger.isInfoEnabled()) { - logger.info("The service ready on spring started. service: " + getInterface()); - } - export(); - } - } - - @Override - @SuppressWarnings({"unchecked", "deprecation"}) - public void afterPropertiesSet() throws Exception { - if (getProvider() == null) { - Map providerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false, false); - if (providerConfigMap != null && providerConfigMap.size() > 0) { - Map protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false); - if ((protocolConfigMap == null || protocolConfigMap.size() == 0) - && providerConfigMap.size() > 1) { // backward compatibility - List providerConfigs = new ArrayList(); - for (ProviderConfig config : providerConfigMap.values()) { - if (config.isDefault() != null && config.isDefault()) { - providerConfigs.add(config); - } - } - if (!providerConfigs.isEmpty()) { - setProviders(providerConfigs); - } - } else { - ProviderConfig providerConfig = null; - for (ProviderConfig config : providerConfigMap.values()) { - if (config.isDefault() == null || config.isDefault()) { - if (providerConfig != null) { - throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config); - } - providerConfig = config; - } - } - if (providerConfig != null) { - setProvider(providerConfig); - } - } - } - } - if (getApplication() == null - && (getProvider() == null || getProvider().getApplication() == null)) { - Map applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false); - if (applicationConfigMap != null && applicationConfigMap.size() > 0) { - ApplicationConfig applicationConfig = null; - for (ApplicationConfig config : applicationConfigMap.values()) { - if (applicationConfig != null) { - throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config); - } - applicationConfig = config; - } - if (applicationConfig != null) { - setApplication(applicationConfig); - } - } - } - if (getModule() == null - && (getProvider() == null || getProvider().getModule() == null)) { - Map moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false, false); - if (moduleConfigMap != null && moduleConfigMap.size() > 0) { - ModuleConfig moduleConfig = null; - for (ModuleConfig config : moduleConfigMap.values()) { - if (config.isDefault() == null || config.isDefault()) { - if (moduleConfig != null) { - throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config); - } - moduleConfig = config; - } - } - if (moduleConfig != null) { - setModule(moduleConfig); - } - } - } - - if (StringUtils.isEmpty(getRegistryIds())) { - if (getApplication() != null && StringUtils.isNotEmpty(getApplication().getRegistryIds())) { - setRegistryIds(getApplication().getRegistryIds()); - } - if (getProvider() != null && StringUtils.isNotEmpty(getProvider().getRegistryIds())) { - setRegistryIds(getProvider().getRegistryIds()); - } - } - - if ((getRegistries() == null || getRegistries().isEmpty()) - && (getProvider() == null || getProvider().getRegistries() == null || getProvider().getRegistries().isEmpty()) - && (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().isEmpty())) { - Map registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false); - if (registryConfigMap != null && registryConfigMap.size() > 0) { - List registryConfigs = new ArrayList<>(); - if (StringUtils.isNotEmpty(registryIds)) { - Arrays.stream(Constants.COMMA_SPLIT_PATTERN.split(registryIds)).forEach(id -> { - if (registryConfigMap.containsKey(id)) { - registryConfigs.add(registryConfigMap.get(id)); - } - }); - } - - if (registryConfigs.isEmpty()) { - for (RegistryConfig config : registryConfigMap.values()) { - if (StringUtils.isEmpty(registryIds)) { - registryConfigs.add(config); - } - } - } - if (!registryConfigs.isEmpty()) { - super.setRegistries(registryConfigs); - } - } - } - if (getMetadataReportConfig() == null) { - Map metadataReportConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MetadataReportConfig.class, false, false); - if (metadataReportConfigMap != null && metadataReportConfigMap.size() == 1) { - super.setMetadataReportConfig(metadataReportConfigMap.values().iterator().next()); - } else if (metadataReportConfigMap != null && metadataReportConfigMap.size() > 1) { - throw new IllegalStateException("Multiple MetadataReport configs: " + metadataReportConfigMap); - } - } - - if (getConfigCenter() == null) { - Map configenterMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ConfigCenterConfig.class, false, false); - if (configenterMap != null && configenterMap.size() == 1) { - super.setConfigCenter(configenterMap.values().iterator().next()); - } else if (configenterMap != null && configenterMap.size() > 1) { - throw new IllegalStateException("Multiple ConfigCenter found:" + configenterMap); - } - } - - if (getMonitor() == null - && (getProvider() == null || getProvider().getMonitor() == null) - && (getApplication() == null || getApplication().getMonitor() == null)) { - Map monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, false, false); - if (monitorConfigMap != null && monitorConfigMap.size() > 0) { - MonitorConfig monitorConfig = null; - for (MonitorConfig config : monitorConfigMap.values()) { - if (config.isDefault() == null || config.isDefault()) { - if (monitorConfig != null) { - throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config); - } - monitorConfig = config; - } - } - if (monitorConfig != null) { - setMonitor(monitorConfig); - } - } - } - - if (StringUtils.isEmpty(getProtocolIds())) { - if (getProvider() != null && StringUtils.isNotEmpty(getProvider().getProtocolIds())) { - setProtocolIds(getProvider().getProtocolIds()); - } - } - - if ((getProtocols() == null || getProtocols().isEmpty()) - && (getProvider() == null || getProvider().getProtocols() == null || getProvider().getProtocols().isEmpty())) { - Map protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false); - if (protocolConfigMap != null && protocolConfigMap.size() > 0) { - List protocolConfigs = new ArrayList(); - if (StringUtils.isNotEmpty(getProtocolIds())) { - Arrays.stream(Constants.COMMA_SPLIT_PATTERN.split(getProtocolIds())) - .forEach(id -> { - if (protocolConfigMap.containsKey(id)) { - protocolConfigs.add(protocolConfigMap.get(id)); - } - }); - } - - if (protocolConfigs.isEmpty()) { - for (ProtocolConfig config : protocolConfigMap.values()) { - if (StringUtils.isEmpty(protocolIds)) { - protocolConfigs.add(config); - } - } - } - - if (!protocolConfigs.isEmpty()) { - super.setProtocols(protocolConfigs); - } - } - } - if (getPath() == null || getPath().length() == 0) { - if (beanName != null && beanName.length() > 0 - && getInterface() != null && getInterface().length() > 0 - && beanName.startsWith(getInterface())) { - setPath(beanName); - } - } - if (!supportedApplicationListener) { - export(); - } - } - - @Override - public void destroy() throws Exception { - // no need to call unexport() here, see - // org.apache.dubbo.config.spring.extension.SpringExtensionFactory.ShutdownHookListener - } - - // merged from dubbox - @Override - protected Class getServiceClass(T ref) { - if (AopUtils.isAopProxy(ref)) { - return AopUtils.getTargetClass(ref); - } - return super.getServiceClass(ref); - } +/* + * 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; + +import org.apache.dubbo.common.Constants; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ConfigCenterConfig; +import org.apache.dubbo.config.MetadataReportConfig; +import org.apache.dubbo.config.ModuleConfig; +import org.apache.dubbo.config.MonitorConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.ProviderConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.ServiceConfig; +import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent; +import org.apache.dubbo.config.spring.extension.SpringExtensionFactory; + +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.factory.BeanFactoryUtils; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import static org.apache.dubbo.config.spring.util.BeanFactoryUtils.addApplicationListener; + +/** + * ServiceFactoryBean + * + * @export + */ +public class ServiceBean extends ServiceConfig implements InitializingBean, DisposableBean, + ApplicationContextAware, ApplicationListener, BeanNameAware, + ApplicationEventPublisherAware { + + + private static final long serialVersionUID = 213195494150089726L; + + private final transient Service service; + + private transient ApplicationContext applicationContext; + + private transient String beanName; + + private transient boolean supportedApplicationListener; + + private ApplicationEventPublisher applicationEventPublisher; + + public ServiceBean() { + super(); + this.service = null; + } + + public ServiceBean(Service service) { + super(service); + this.service = service; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + SpringExtensionFactory.addApplicationContext(applicationContext); + supportedApplicationListener = addApplicationListener(applicationContext, this); + } + + @Override + public void setBeanName(String name) { + this.beanName = name; + } + + /** + * Gets associated {@link Service} + * + * @return associated {@link Service} + */ + public Service getService() { + return service; + } + + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + if (!isExported() && !isUnexported()) { + if (logger.isInfoEnabled()) { + logger.info("The service ready on spring started. service: " + getInterface()); + } + export(); + } + } + + @Override + @SuppressWarnings({"unchecked", "deprecation"}) + public void afterPropertiesSet() throws Exception { + if (getProvider() == null) { + Map providerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false, false); + if (providerConfigMap != null && providerConfigMap.size() > 0) { + Map protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false); + if ((protocolConfigMap == null || protocolConfigMap.size() == 0) + && providerConfigMap.size() > 1) { // backward compatibility + List providerConfigs = new ArrayList(); + for (ProviderConfig config : providerConfigMap.values()) { + if (config.isDefault() != null && config.isDefault()) { + providerConfigs.add(config); + } + } + if (!providerConfigs.isEmpty()) { + setProviders(providerConfigs); + } + } else { + ProviderConfig providerConfig = null; + for (ProviderConfig config : providerConfigMap.values()) { + if (config.isDefault() == null || config.isDefault()) { + if (providerConfig != null) { + throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config); + } + providerConfig = config; + } + } + if (providerConfig != null) { + setProvider(providerConfig); + } + } + } + } + if (getApplication() == null + && (getProvider() == null || getProvider().getApplication() == null)) { + Map applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false); + if (applicationConfigMap != null && applicationConfigMap.size() > 0) { + ApplicationConfig applicationConfig = null; + for (ApplicationConfig config : applicationConfigMap.values()) { + if (applicationConfig != null) { + throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config); + } + applicationConfig = config; + } + if (applicationConfig != null) { + setApplication(applicationConfig); + } + } + } + if (getModule() == null + && (getProvider() == null || getProvider().getModule() == null)) { + Map moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false, false); + if (moduleConfigMap != null && moduleConfigMap.size() > 0) { + ModuleConfig moduleConfig = null; + for (ModuleConfig config : moduleConfigMap.values()) { + if (config.isDefault() == null || config.isDefault()) { + if (moduleConfig != null) { + throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config); + } + moduleConfig = config; + } + } + if (moduleConfig != null) { + setModule(moduleConfig); + } + } + } + + if (StringUtils.isEmpty(getRegistryIds())) { + if (getApplication() != null && StringUtils.isNotEmpty(getApplication().getRegistryIds())) { + setRegistryIds(getApplication().getRegistryIds()); + } + if (getProvider() != null && StringUtils.isNotEmpty(getProvider().getRegistryIds())) { + setRegistryIds(getProvider().getRegistryIds()); + } + } + + if ((getRegistries() == null || getRegistries().isEmpty()) + && (getProvider() == null || getProvider().getRegistries() == null || getProvider().getRegistries().isEmpty()) + && (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().isEmpty())) { + Map registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false); + if (registryConfigMap != null && registryConfigMap.size() > 0) { + List registryConfigs = new ArrayList<>(); + if (StringUtils.isNotEmpty(registryIds)) { + Arrays.stream(Constants.COMMA_SPLIT_PATTERN.split(registryIds)).forEach(id -> { + if (registryConfigMap.containsKey(id)) { + registryConfigs.add(registryConfigMap.get(id)); + } + }); + } + + if (registryConfigs.isEmpty()) { + for (RegistryConfig config : registryConfigMap.values()) { + if (StringUtils.isEmpty(registryIds)) { + registryConfigs.add(config); + } + } + } + if (!registryConfigs.isEmpty()) { + super.setRegistries(registryConfigs); + } + } + } + if (getMetadataReportConfig() == null) { + Map metadataReportConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MetadataReportConfig.class, false, false); + if (metadataReportConfigMap != null && metadataReportConfigMap.size() == 1) { + super.setMetadataReportConfig(metadataReportConfigMap.values().iterator().next()); + } else if (metadataReportConfigMap != null && metadataReportConfigMap.size() > 1) { + throw new IllegalStateException("Multiple MetadataReport configs: " + metadataReportConfigMap); + } + } + + if (getConfigCenter() == null) { + Map configenterMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ConfigCenterConfig.class, false, false); + if (configenterMap != null && configenterMap.size() == 1) { + super.setConfigCenter(configenterMap.values().iterator().next()); + } else if (configenterMap != null && configenterMap.size() > 1) { + throw new IllegalStateException("Multiple ConfigCenter found:" + configenterMap); + } + } + + if (getMonitor() == null + && (getProvider() == null || getProvider().getMonitor() == null) + && (getApplication() == null || getApplication().getMonitor() == null)) { + Map monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, false, false); + if (monitorConfigMap != null && monitorConfigMap.size() > 0) { + MonitorConfig monitorConfig = null; + for (MonitorConfig config : monitorConfigMap.values()) { + if (config.isDefault() == null || config.isDefault()) { + if (monitorConfig != null) { + throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config); + } + monitorConfig = config; + } + } + if (monitorConfig != null) { + setMonitor(monitorConfig); + } + } + } + + if (StringUtils.isEmpty(getProtocolIds())) { + if (getProvider() != null && StringUtils.isNotEmpty(getProvider().getProtocolIds())) { + setProtocolIds(getProvider().getProtocolIds()); + } + } + + if ((getProtocols() == null || getProtocols().isEmpty()) + && (getProvider() == null || getProvider().getProtocols() == null || getProvider().getProtocols().isEmpty())) { + Map protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false); + if (protocolConfigMap != null && protocolConfigMap.size() > 0) { + List protocolConfigs = new ArrayList(); + if (StringUtils.isNotEmpty(getProtocolIds())) { + Arrays.stream(Constants.COMMA_SPLIT_PATTERN.split(getProtocolIds())) + .forEach(id -> { + if (protocolConfigMap.containsKey(id)) { + protocolConfigs.add(protocolConfigMap.get(id)); + } + }); + } + + if (protocolConfigs.isEmpty()) { + for (ProtocolConfig config : protocolConfigMap.values()) { + if (StringUtils.isEmpty(protocolIds)) { + protocolConfigs.add(config); + } + } + } + + if (!protocolConfigs.isEmpty()) { + super.setProtocols(protocolConfigs); + } + } + } + if (getPath() == null || getPath().length() == 0) { + if (beanName != null && beanName.length() > 0 + && getInterface() != null && getInterface().length() > 0 + && beanName.startsWith(getInterface())) { + setPath(beanName); + } + } + if (!supportedApplicationListener) { + export(); + } + } + + /** + * Get the name of {@link ServiceBean} + * + * @return {@link ServiceBean}'s name + * @since 2.6.5 + */ + public String getBeanName() { + return this.beanName; + } + + /** + * @since 2.6.5 + */ + @Override + public void export() { + super.export(); + // Publish ServiceBeanExportedEvent + publishExportEvent(); + } + + /** + * @since 2.6.5 + */ + private void publishExportEvent() { + ServiceBeanExportedEvent exportEvent = new ServiceBeanExportedEvent(this); + applicationEventPublisher.publishEvent(exportEvent); + } + + @Override + public void destroy() throws Exception { + // no need to call unexport() here, see + // org.apache.dubbo.config.spring.extension.SpringExtensionFactory.ShutdownHookListener + } + + // merged from dubbox + @Override + protected Class getServiceClass(T ref) { + if (AopUtils.isAopProxy(ref)) { + return AopUtils.getTargetClass(ref); + } + return super.getServiceClass(ref); + } + + /** + * @param applicationEventPublisher + * @since 2.6.5 + */ + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.applicationEventPublisher = applicationEventPublisher; + } } \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java index eb99855e72b..7f7afd98d66 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java @@ -77,7 +77,7 @@ public final B build() throws Exception { configureBean(bean); if (logger.isInfoEnabled()) { - logger.info(bean + " has been built."); + logger.info("The bean[type:" + bean.getClass().getSimpleName() + "] has been built."); } return bean; @@ -175,7 +175,7 @@ private void configureModuleConfig(B bean) { /** - * Resolves the bean ids of {@link org.apache.dubbo.config.RegistryConfig} + * Resolves the bean ids of {@link RegistryConfig} * * @param annotation {@link A} * @return non-empty array diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java new file mode 100644 index 00000000000..1dc147f0dda --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java @@ -0,0 +1,529 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.config.spring.beans.factory.annotation; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.PropertyValues; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.annotation.InjectionMetadata; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; +import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.EnvironmentAware; +import org.springframework.core.Ordered; +import org.springframework.core.PriorityOrdered; +import org.springframework.core.env.Environment; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringUtils; + +import java.beans.PropertyDescriptor; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static org.apache.dubbo.config.spring.util.ClassUtils.resolveGenericType; +import static org.springframework.core.BridgeMethodResolver.findBridgedMethod; +import static org.springframework.core.BridgeMethodResolver.isVisibilityBridgeMethodPair; +import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; +import static org.springframework.core.annotation.AnnotationUtils.getAnnotation; + +/** + * Abstract generic {@link BeanPostProcessor} implementation for customized annotation that annotated injected-object. + * + * The source code is cloned from https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java + * + * @since 2.6.6 + */ +public abstract class AnnotationInjectedBeanPostProcessor extends + InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, + BeanFactoryAware, BeanClassLoaderAware, EnvironmentAware, DisposableBean { + + private final static int CACHE_SIZE = Integer.getInteger("", 32); + + private final Log logger = LogFactory.getLog(getClass()); + + private final Class annotationType; + + private final ConcurrentMap injectionMetadataCache = + new ConcurrentHashMap(CACHE_SIZE); + + private final ConcurrentMap injectedObjectsCache = new ConcurrentHashMap(CACHE_SIZE); + + private ConfigurableListableBeanFactory beanFactory; + + private Environment environment; + + private ClassLoader classLoader; + + private int order = Ordered.LOWEST_PRECEDENCE; + + public AnnotationInjectedBeanPostProcessor() { + this.annotationType = resolveGenericType(getClass()); + } + + private static Collection combine(Collection... elements) { + List allElements = new ArrayList(); + for (Collection e : elements) { + allElements.addAll(e); + } + return allElements; + } + + /** + * Annotation type + * + * @return non-null + */ + public final Class getAnnotationType() { + return annotationType; + } + + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory, + "AnnotationInjectedBeanPostProcessor requires a ConfigurableListableBeanFactory"); + this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; + } + + @Override + public PropertyValues postProcessPropertyValues( + PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException { + + InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs); + try { + metadata.inject(bean, beanName, pvs); + } catch (BeanCreationException ex) { + throw ex; + } catch (Throwable ex) { + throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getName() + + " dependencies is failed", ex); + } + return pvs; + } + + + /** + * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link A} fields + * + * @param beanClass The {@link Class} of Bean + * @return non-null {@link List} + */ + private List findFieldAnnotationMetadata(final Class beanClass) { + + final List elements = new LinkedList(); + + ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() { + @Override + public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { + + A annotation = getAnnotation(field, getAnnotationType()); + + if (annotation != null) { + + if (Modifier.isStatic(field.getModifiers())) { + if (logger.isWarnEnabled()) { + logger.warn("@" + getAnnotationType().getName() + " is not supported on static fields: " + field); + } + return; + } + + elements.add(new AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement(field, annotation)); + } + + } + }); + + return elements; + + } + + /** + * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link A @A} methods + * + * @param beanClass The {@link Class} of Bean + * @return non-null {@link List} + */ + private List findAnnotatedMethodMetadata(final Class beanClass) { + + final List elements = new LinkedList(); + + ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() { + @Override + public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { + + Method bridgedMethod = findBridgedMethod(method); + + if (!isVisibilityBridgeMethodPair(method, bridgedMethod)) { + return; + } + + A annotation = findAnnotation(bridgedMethod, getAnnotationType()); + + if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) { + if (Modifier.isStatic(method.getModifiers())) { + if (logger.isWarnEnabled()) { + logger.warn("@" + getAnnotationType().getSimpleName() + " annotation is not supported on static methods: " + method); + } + return; + } + if (method.getParameterTypes().length == 0) { + if (logger.isWarnEnabled()) { + logger.warn("@" + getAnnotationType().getSimpleName() + " annotation should only be used on methods with parameters: " + + method); + } + } + PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass); + elements.add(new AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement(method, pd, annotation)); + } + } + }); + + return elements; + + } + + + private AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class beanClass) { + Collection fieldElements = findFieldAnnotationMetadata(beanClass); + Collection methodElements = findAnnotatedMethodMetadata(beanClass); + return new AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements); + + } + + private InjectionMetadata findInjectionMetadata(String beanName, Class clazz, PropertyValues pvs) { + // Fall back to class name as cache key, for backwards compatibility with custom callers. + String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); + // Quick check on the concurrent map first, with minimal locking. + AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); + if (InjectionMetadata.needsRefresh(metadata, clazz)) { + synchronized (this.injectionMetadataCache) { + metadata = this.injectionMetadataCache.get(cacheKey); + if (InjectionMetadata.needsRefresh(metadata, clazz)) { + if (metadata != null) { + metadata.clear(pvs); + } + try { + metadata = buildAnnotatedMetadata(clazz); + this.injectionMetadataCache.put(cacheKey, metadata); + } catch (NoClassDefFoundError err) { + throw new IllegalStateException("Failed to introspect object class [" + clazz.getName() + + "] for annotation metadata: could not find class that it depends on", err); + } + } + } + } + return metadata; + } + + @Override + public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) { + if (beanType != null) { + InjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null); + metadata.checkConfigMembers(beanDefinition); + } + } + + @Override + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + + @Override + public void destroy() throws Exception { + + for (Object object : injectedObjectsCache.values()) { + if (logger.isInfoEnabled()) { + logger.info(object + " was destroying!"); + } + + if (object instanceof DisposableBean) { + ((DisposableBean) object).destroy(); + } + } + + injectionMetadataCache.clear(); + injectedObjectsCache.clear(); + + if (logger.isInfoEnabled()) { + logger.info(getClass() + " was destroying!"); + } + + } + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + protected Environment getEnvironment() { + return environment; + } + + protected ClassLoader getClassLoader() { + return classLoader; + } + + protected ConfigurableListableBeanFactory getBeanFactory() { + return beanFactory; + } + + /** + * Gets all injected-objects. + * + * @return non-null {@link Collection} + */ + protected Collection getInjectedObjects() { + return this.injectedObjectsCache.values(); + } + + /** + * Get injected-object from specified {@link A annotation} and Bean Class + * + * @param annotation {@link A annotation} + * @param bean Current bean that will be injected + * @param beanName Current bean name that will be injected + * @param injectedType the type of injected-object + * @param injectedElement {@link InjectionMetadata.InjectedElement} + * @return An injected object + * @throws Exception If getting is failed + */ + protected Object getInjectedObject(A annotation, Object bean, String beanName, Class injectedType, + InjectionMetadata.InjectedElement injectedElement) throws Exception { + + String cacheKey = buildInjectedObjectCacheKey(annotation, bean, beanName, injectedType, injectedElement); + + Object injectedObject = injectedObjectsCache.get(cacheKey); + + if (injectedObject == null) { + injectedObject = doGetInjectedBean(annotation, bean, beanName, injectedType, injectedElement); + // Customized inject-object if necessary + injectedObjectsCache.putIfAbsent(cacheKey, injectedObject); + } + + return injectedObject; + + } + + /** + * Subclass must implement this method to get injected-object. The context objects could help this method if + * necessary : + *
    + *
  • {@link #getBeanFactory() BeanFactory}
  • + *
  • {@link #getClassLoader() ClassLoader}
  • + *
  • {@link #getEnvironment() Environment}
  • + *
+ * + * @param annotation {@link A annotation} + * @param bean Current bean that will be injected + * @param beanName Current bean name that will be injected + * @param injectedType the type of injected-object + * @param injectedElement {@link InjectionMetadata.InjectedElement} + * @return The injected object + * @throws Exception If resolving an injected object is failed. + */ + protected abstract Object doGetInjectedBean(A annotation, Object bean, String beanName, Class injectedType, + InjectionMetadata.InjectedElement injectedElement) throws Exception; + + /** + * Build a cache key for injected-object. The context objects could help this method if + * necessary : + *
    + *
  • {@link #getBeanFactory() BeanFactory}
  • + *
  • {@link #getClassLoader() ClassLoader}
  • + *
  • {@link #getEnvironment() Environment}
  • + *
+ * + * @param annotation {@link A annotation} + * @param bean Current bean that will be injected + * @param beanName Current bean name that will be injected + * @param injectedType the type of injected-object + * @param injectedElement {@link InjectionMetadata.InjectedElement} + * @return Bean cache key + */ + protected abstract String buildInjectedObjectCacheKey(A annotation, Object bean, String beanName, + Class injectedType, + InjectionMetadata.InjectedElement injectedElement); + + /** + * Get {@link Map} in injected field. + * + * @return non-null ready-only {@link Map} + */ + protected Map getInjectedFieldObjectsMap() { + + Map injectedElementBeanMap = + new LinkedHashMap(); + + for (AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata metadata : injectionMetadataCache.values()) { + + Collection fieldElements = metadata.getFieldElements(); + + for (AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement fieldElement : fieldElements) { + + injectedElementBeanMap.put(fieldElement, fieldElement.bean); + + } + + } + + return Collections.unmodifiableMap(injectedElementBeanMap); + + } + + /** + * Get {@link Map} in injected method. + * + * @return non-null {@link Map} + */ + protected Map getInjectedMethodObjectsMap() { + + Map injectedElementBeanMap = + new LinkedHashMap(); + + for (AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata metadata : injectionMetadataCache.values()) { + + Collection methodElements = metadata.getMethodElements(); + + for (AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement methodElement : methodElements) { + + injectedElementBeanMap.put(methodElement, methodElement.object); + + } + + } + + return Collections.unmodifiableMap(injectedElementBeanMap); + + } + + /** + * {@link A} {@link InjectionMetadata} implementation + */ + private class AnnotatedInjectionMetadata extends InjectionMetadata { + + private final Collection fieldElements; + + private final Collection methodElements; + + public AnnotatedInjectionMetadata(Class targetClass, Collection fieldElements, + Collection methodElements) { + super(targetClass, combine(fieldElements, methodElements)); + this.fieldElements = fieldElements; + this.methodElements = methodElements; + } + + public Collection getFieldElements() { + return fieldElements; + } + + public Collection getMethodElements() { + return methodElements; + } + } + + /** + * {@link A} {@link Method} {@link InjectionMetadata.InjectedElement} + */ + private class AnnotatedMethodElement extends InjectionMetadata.InjectedElement { + + private final Method method; + + private final A annotation; + + private volatile Object object; + + protected AnnotatedMethodElement(Method method, PropertyDescriptor pd, A annotation) { + super(method, pd); + this.method = method; + this.annotation = annotation; + } + + @Override + protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { + + Class injectedType = pd.getPropertyType(); + + Object injectedObject = getInjectedObject(annotation, bean, beanName, injectedType, this); + + ReflectionUtils.makeAccessible(method); + + method.invoke(bean, injectedObject); + + } + + } + + /** + * {@link A} {@link Field} {@link InjectionMetadata.InjectedElement} + */ + public class AnnotatedFieldElement extends InjectionMetadata.InjectedElement { + + private final Field field; + + private final A annotation; + + private volatile Object bean; + + protected AnnotatedFieldElement(Field field, A annotation) { + super(field, null); + this.field = field; + this.annotation = annotation; + } + + @Override + protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { + + Class injectedType = field.getType(); + + Object injectedObject = getInjectedObject(annotation, bean, beanName, injectedType, this); + + ReflectionUtils.makeAccessible(field); + + field.set(bean, injectedObject); + + } + + } +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/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 65aadeff359..96c4d3885b0 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 @@ -76,7 +76,7 @@ public DubboConfigBindingBeanPostProcessor(String prefix, String beanName) { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - if (beanName != null && beanName.equals(this.beanName) && bean instanceof AbstractConfig) { + if (beanName.equals(this.beanName) && bean instanceof AbstractConfig) { AbstractConfig dubboConfig = (AbstractConfig) bean; 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 4d8f0bdd29e..82fb9b25eb0 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,582 +16,237 @@ */ package org.apache.dubbo.config.spring.beans.factory.annotation; -import org.apache.dubbo.common.Constants; -import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.spring.ReferenceBean; +import org.apache.dubbo.config.spring.ServiceBean; +import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent; +import org.apache.dubbo.config.spring.util.AnnotationUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.BeanUtils; import org.springframework.beans.BeansException; -import org.springframework.beans.PropertyValues; -import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.annotation.InjectionMetadata; -import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; -import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor; -import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; -import org.springframework.core.PriorityOrdered; -import org.springframework.core.env.Environment; -import org.springframework.util.ClassUtils; -import org.springframework.util.ConcurrentReferenceHashMap; -import org.springframework.util.ObjectUtils; -import org.springframework.util.ReflectionUtils; - -import java.beans.PropertyDescriptor; -import java.lang.annotation.Annotation; +import org.springframework.context.ApplicationEvent; +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.Modifier; -import java.util.ArrayList; +import java.lang.reflect.Proxy; import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; +import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import static org.springframework.core.BridgeMethodResolver.findBridgedMethod; -import static org.springframework.core.BridgeMethodResolver.isVisibilityBridgeMethodPair; -import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; -import static org.springframework.core.annotation.AnnotationUtils.getAnnotation; - /** * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation * that Consumer service {@link Reference} annotated fields * * @since 2.5.7 */ -public class ReferenceAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter - implements MergedBeanDefinitionPostProcessor, PriorityOrdered, ApplicationContextAware, BeanClassLoaderAware, - DisposableBean { +public class ReferenceAnnotationBeanPostProcessor extends AnnotationInjectedBeanPostProcessor + implements ApplicationContextAware, ApplicationListener { /** * The bean name of {@link ReferenceAnnotationBeanPostProcessor} */ public static final String BEAN_NAME = "referenceAnnotationBeanPostProcessor"; - private final Log logger = LogFactory.getLog(getClass()); - - private ApplicationContext applicationContext; - - private ClassLoader classLoader; + /** + * Cache size + */ + private static final int CACHE_SIZE = Integer.getInteger(BEAN_NAME + ".cache.size", 32); - private final ConcurrentMap injectionMetadataCache = - new ConcurrentHashMap(256); + private final ConcurrentMap> referenceBeanCache = + new ConcurrentHashMap>(CACHE_SIZE); - private final ConcurrentMap> referenceBeansCache = - new ConcurrentHashMap>(); + private final ConcurrentHashMap localReferenceBeanInvocationHandlerCache = + new ConcurrentHashMap(CACHE_SIZE); - private static final Map, List> annotationMethodsCache = - new ConcurrentReferenceHashMap, List>(256); + private final ConcurrentMap> injectedFieldReferenceBeanCache = + new ConcurrentHashMap>(CACHE_SIZE); - @Override - public PropertyValues postProcessPropertyValues( - PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException { - - InjectionMetadata metadata = findReferenceMetadata(beanName, bean.getClass(), pvs); - try { - metadata.inject(bean, beanName, pvs); - } catch (BeanCreationException ex) { - throw ex; - } catch (Throwable ex) { - throw new BeanCreationException(beanName, "Injection of @Reference dependencies failed", ex); - } - return pvs; - } + private final ConcurrentMap> injectedMethodReferenceBeanCache = + new ConcurrentHashMap>(CACHE_SIZE); + private ApplicationContext applicationContext; /** - * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link Reference @Reference} fields + * Gets all beans of {@link ReferenceBean} * - * @param beanClass The {@link Class} of Bean - * @return non-null {@link List} + * @return non-null read-only {@link Collection} + * @since 2.5.9 */ - private List findFieldReferenceMetadata(final Class beanClass) { - - final List elements = new LinkedList(); - - ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() { - @Override - public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { - - Reference reference = getAnnotation(field, Reference.class); - - if (reference != null) { - - if (Modifier.isStatic(field.getModifiers())) { - if (logger.isWarnEnabled()) { - logger.warn("@Reference annotation is not supported on static fields: " + field); - } - return; - } - - elements.add(new ReferenceFieldElement(field, reference)); - } - - } - }); - - return elements; - + public Collection> getReferenceBeans() { + return referenceBeanCache.values(); } /** - * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link Reference @Reference} methods + * Get {@link ReferenceBean} {@link Map} in injected field. * - * @param beanClass The {@link Class} of Bean - * @return non-null {@link List} + * @return non-null {@link Map} + * @since 2.5.11 */ - private List findMethodReferenceMetadata(final Class beanClass) { - - final List elements = new LinkedList(); - - ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() { - @Override - public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { - - Method bridgedMethod = findBridgedMethod(method); - - if (!isVisibilityBridgeMethodPair(method, bridgedMethod)) { - return; - } - - Reference reference = findAnnotation(bridgedMethod, Reference.class); - - if (reference != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) { - if (Modifier.isStatic(method.getModifiers())) { - if (logger.isWarnEnabled()) { - logger.warn("@Reference annotation is not supported on static methods: " + method); - } - return; - } - if (method.getParameterTypes().length == 0) { - if (logger.isWarnEnabled()) { - logger.warn("@Reference annotation should only be used on methods with parameters: " + - method); - } - } - PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass); - elements.add(new ReferenceMethodElement(method, pd, reference)); - } - } - }); - - return elements; - + public Map> getInjectedFieldReferenceBeanMap() { + return Collections.unmodifiableMap(injectedFieldReferenceBeanCache); } - /** - * @param beanClass - * @return + * Get {@link ReferenceBean} {@link Map} in injected method. + * + * @return non-null {@link Map} + * @since 2.5.11 */ - private ReferenceInjectionMetadata buildReferenceMetadata(final Class beanClass) { - Collection fieldElements = findFieldReferenceMetadata(beanClass); - Collection methodElements = findMethodReferenceMetadata(beanClass); - return new ReferenceInjectionMetadata(beanClass, fieldElements, methodElements); - - } - - private InjectionMetadata findReferenceMetadata(String beanName, Class clazz, PropertyValues pvs) { - // Fall back to class name as cache key, for backwards compatibility with custom callers. - String cacheKey = (StringUtils.isNotEmpty(beanName) ? beanName : clazz.getName()); - // Quick check on the concurrent map first, with minimal locking. - ReferenceInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); - if (InjectionMetadata.needsRefresh(metadata, clazz)) { - synchronized (this.injectionMetadataCache) { - metadata = this.injectionMetadataCache.get(cacheKey); - if (InjectionMetadata.needsRefresh(metadata, clazz)) { - if (metadata != null) { - metadata.clear(pvs); - } - try { - metadata = buildReferenceMetadata(clazz); - this.injectionMetadataCache.put(cacheKey, metadata); - } catch (NoClassDefFoundError err) { - throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() + - "] for reference metadata: could not find class that it depends on", err); - } - } - } - } - return metadata; - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } - - @Override - public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) { - if (beanType != null) { - InjectionMetadata metadata = findReferenceMetadata(beanName, beanType, null); - metadata.checkConfigMembers(beanDefinition); - } + public Map> getInjectedMethodReferenceBeanMap() { + return Collections.unmodifiableMap(injectedMethodReferenceBeanCache); } @Override - public int getOrder() { - return LOWEST_PRECEDENCE; - } + protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class injectedType, + InjectionMetadata.InjectedElement injectedElement) throws Exception { - @Override - public void destroy() throws Exception { + String referencedBeanName = buildReferencedBeanName(reference, injectedType); - for (ReferenceBean referenceBean : referenceBeansCache.values()) { - if (logger.isInfoEnabled()) { - logger.info(referenceBean + " was destroying!"); - } - referenceBean.destroy(); - } + ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referencedBeanName, reference, injectedType, getClassLoader()); - injectionMetadataCache.clear(); - referenceBeansCache.clear(); + cacheInjectedReferenceBean(referenceBean, injectedElement); - if (logger.isInfoEnabled()) { - logger.info(getClass() + " was destroying!"); - } + Object proxy = buildProxy(referencedBeanName, referenceBean, injectedType); + return proxy; } - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } - - - /** - * Gets all beans of {@link ReferenceBean} - * - * @return non-null {@link Collection} - * @since 2.5.9 - */ - public Collection> getReferenceBeans() { - return this.referenceBeansCache.values(); + private Object buildProxy(String referencedBeanName, ReferenceBean referenceBean, Class injectedType) { + InvocationHandler handler = buildInvocationHandler(referencedBeanName, referenceBean); + Object proxy = Proxy.newProxyInstance(getClassLoader(), new Class[]{injectedType}, handler); + return proxy; } + private InvocationHandler buildInvocationHandler(String referencedBeanName, ReferenceBean referenceBean) { - /** - * {@link Reference} {@link InjectionMetadata} implementation - * - * @since 2.5.11 - */ - private static class ReferenceInjectionMetadata extends InjectionMetadata { - - private final Collection fieldElements; - - private final Collection methodElements; - + ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.get(referencedBeanName); - public ReferenceInjectionMetadata(Class targetClass, Collection fieldElements, - Collection methodElements) { - super(targetClass, combine(fieldElements, methodElements)); - this.fieldElements = fieldElements; - this.methodElements = methodElements; + if (handler == null) { + handler = new ReferenceBeanInvocationHandler(referenceBean); } - private static Collection combine(Collection... elements) { - List allElements = new ArrayList(); - for (Collection e : elements) { - allElements.addAll(e); - } - return allElements; - } - - public Collection getFieldElements() { - return fieldElements; + if (applicationContext.containsBean(referencedBeanName)) { // Is local @Service Bean or not ? + // ReferenceBeanInvocationHandler's initialization has to wait for current local @Service Bean has been exported. + localReferenceBeanInvocationHandlerCache.put(referencedBeanName, handler); + } else { + // Remote Reference Bean should initialize immediately + handler.init(); } - public Collection getMethodElements() { - return methodElements; - } + return handler; } - /** - * {@link Reference} {@link Method} {@link InjectionMetadata.InjectedElement} - */ - private class ReferenceMethodElement extends InjectionMetadata.InjectedElement { + private static class ReferenceBeanInvocationHandler implements InvocationHandler { - private final Method method; + private final ReferenceBean referenceBean; - private final Reference reference; + private Object bean; - private volatile ReferenceBean referenceBean; - - protected ReferenceMethodElement(Method method, PropertyDescriptor pd, Reference reference) { - super(method, pd); - this.method = method; - this.reference = reference; + private ReferenceBeanInvocationHandler(ReferenceBean referenceBean) { + this.referenceBean = referenceBean; } @Override - protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { - - Class referenceClass = pd.getPropertyType(); - - referenceBean = buildReferenceBean(reference, referenceClass); - - ReflectionUtils.makeAccessible(method); - - method.invoke(bean, referenceBean.getObject()); - + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + return method.invoke(bean, args); } - } - - /** - * {@link Reference} {@link Field} {@link InjectionMetadata.InjectedElement} - */ - private class ReferenceFieldElement extends InjectionMetadata.InjectedElement { - - private final Field field; - - private final Reference reference; - - private volatile ReferenceBean referenceBean; - - protected ReferenceFieldElement(Field field, Reference reference) { - super(field, null); - this.field = field; - this.reference = reference; + private void init() { + this.bean = referenceBean.get(); } + } - @Override - protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { - - Class referenceClass = field.getType(); + @Override + protected String buildInjectedObjectCacheKey(Reference reference, Object bean, String beanName, + Class injectedType, InjectionMetadata.InjectedElement injectedElement) { - referenceBean = buildReferenceBean(reference, referenceClass); + String key = buildReferencedBeanName(reference, injectedType) + + "#source=" + (injectedElement.getMember()) + + "#attributes=" + AnnotationUtils.getAttributes(reference,getEnvironment(),true); - ReflectionUtils.makeAccessible(field); + return key; + } - field.set(bean, referenceBean.getObject()); + private String buildReferencedBeanName(Reference reference, Class injectedType) { - } + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, injectedType, getEnvironment()); + return getEnvironment().resolvePlaceholders(builder.build()); } - private ReferenceBean buildReferenceBean(Reference reference, Class referenceClass) throws Exception { - - String referenceBeanCacheKey = generateReferenceBeanCacheKey(reference, referenceClass); + private ReferenceBean buildReferenceBeanIfAbsent(String referencedBeanName, Reference reference, + Class referencedType, ClassLoader classLoader) + throws Exception { - ReferenceBean referenceBean = referenceBeansCache.get(referenceBeanCacheKey); + ReferenceBean referenceBean = referenceBeanCache.get(referencedBeanName); if (referenceBean == null) { - ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder .create(reference, classLoader, applicationContext) - .interfaceClass(referenceClass); - + .interfaceClass(referencedType); referenceBean = beanBuilder.build(); - - referenceBeansCache.putIfAbsent(referenceBeanCacheKey, referenceBean); - + referenceBeanCache.put(referencedBeanName, referenceBean); } return referenceBean; - - } - - - /** - * Generate a cache key of {@link ReferenceBean} - * - * @param reference {@link Reference} - * @param beanClass {@link Class} - * @return - */ - private String generateReferenceBeanCacheKey(Reference reference, Class beanClass) { - - String key = resolveReferenceKey(annotationValues(reference)); - - Environment environment = applicationContext.getEnvironment(); - - key = environment.resolvePlaceholders(key); - - return key; - } - private static String resolveInterfaceName(Reference reference, Class beanClass) - throws IllegalStateException { - - String interfaceName; - if (!"".equals(reference.interfaceName())) { - interfaceName = reference.interfaceName(); - } else if (!void.class.equals(reference.interfaceClass())) { - interfaceName = reference.interfaceClass().getName(); - } else if (beanClass.isInterface()) { - interfaceName = beanClass.getName(); - } else { - throw new IllegalStateException( - "The @Reference undefined interfaceClass or interfaceName, and the property type " - + beanClass.getName() + " is not a interface."); + private void cacheInjectedReferenceBean(ReferenceBean referenceBean, + InjectionMetadata.InjectedElement injectedElement) { + if (injectedElement.getMember() instanceof Field) { + injectedFieldReferenceBeanCache.put(injectedElement, referenceBean); + } else if (injectedElement.getMember() instanceof Method) { + injectedMethodReferenceBeanCache.put(injectedElement, referenceBean); } - - return interfaceName; - } - - /** - * 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; - + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; } - /** - * 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); - - } - + @Override + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof ServiceBeanExportedEvent) { + onServiceBeanExportEvent((ServiceBeanExportedEvent) event); + } else if (event instanceof ContextRefreshedEvent) { + onContextRefreshedEvent((ContextRefreshedEvent) event); } - - 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); - - } - - /** - * Generate a key based on the annotation. - * - * @param annotations annotation value - * @return unique key, never null will be returned. - * @since 2.7.0 - */ - private String resolveReferenceKey(Map annotations) { - Iterator> annotationVisitor = annotations.entrySet().iterator(); - StringBuilder builder = new StringBuilder(); - while (annotationVisitor.hasNext()) { - Map.Entry attribute = annotationVisitor.next(); - String attributeValue = null; - if (attribute.getValue() instanceof String[]) { - attributeValue = toPlainString((String[]) attribute.getValue()); - } else { - attributeValue = attribute.getValue() == null ? "" : attribute.getValue().toString(); - } - - if (StringUtils.isNotEmpty(attributeValue)) { - if (builder.length() > 0) { - builder.append(Constants.PATH_SEPARATOR); - } - builder.append(attributeValue); - } - } - return builder.toString(); + private void onServiceBeanExportEvent(ServiceBeanExportedEvent event) { + ServiceBean serviceBean = event.getServiceBean(); + initReferenceBeanInvocationHandler(serviceBean); } - private Map annotationValues(Annotation annotation) { - Map annotations = new LinkedHashMap<>(); - - for (Method method : getAnnotationMethods(annotation.annotationType())) { - try { - Object attributeValue = method.invoke(annotation); - Object defaultValue = method.getDefaultValue(); - if (nullSafeEquals(attributeValue, defaultValue)) { - continue; - } - annotations.put(method.getName(), attributeValue); - } catch (Throwable e) { - throw new IllegalStateException("Failed to obtain annotation attribute value for " + method, e); - } + private void initReferenceBeanInvocationHandler(ServiceBean serviceBean) { + String serviceBeanName = serviceBean.getBeanName(); + // Remove ServiceBean when it's exported + ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.remove(serviceBeanName); + // Initialize + if (handler != null) { + handler.init(); } - return annotations; } - private static List getAnnotationMethods(Class annotationType) { - List methods = annotationMethodsCache.get(annotationType); - if (methods != null) { - return methods; - } - - methods = new ArrayList(); - for (Method method : annotationType.getDeclaredMethods()) { - if (isAnnotationMethod(method)) { - ReflectionUtils.makeAccessible(method); - methods.add(method); - } - } + private void onContextRefreshedEvent(ContextRefreshedEvent event) { - annotationMethodsCache.put(annotationType, methods); - return methods; } - private static boolean isAnnotationMethod(Method method) { - return (method != null - && method.getParameterTypes().length == 0 - && method.getReturnType() != void.class); - } - private static boolean nullSafeEquals(Object first, Object another) { - return ObjectUtils.nullSafeEquals(first, another); - } - - private String toPlainString(String[] array) { - if (array == null || array.length == 0) { - return ""; - } - StringBuilder buffer = new StringBuilder(); - for (int i = 0; i < array.length; i++) { - if (i > 0) { - buffer.append(Constants.COMMA_SEPARATOR); - } - buffer.append(array[i]); - } - return buffer.toString(); + @Override + public void destroy() throws Exception { + super.destroy(); + this.referenceBeanCache.clear(); + this.localReferenceBeanInvocationHandlerCache.clear(); + this.injectedFieldReferenceBeanCache.clear(); + this.injectedMethodReferenceBeanCache.clear(); } } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java index 617b5f15ff9..d415bf76efe 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java @@ -16,22 +16,24 @@ */ package org.apache.dubbo.config.spring.beans.factory.annotation; +import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.config.ConsumerConfig; import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.spring.ReferenceBean; -import org.apache.dubbo.config.spring.convert.converter.StringArrayToMapConverter; -import org.apache.dubbo.config.spring.convert.converter.StringArrayToStringConverter; +import org.springframework.beans.propertyeditors.StringTrimmerEditor; import org.springframework.context.ApplicationContext; -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springframework.validation.DataBinder; +import java.beans.PropertyEditorSupport; +import java.util.Map; + import static org.apache.dubbo.config.spring.util.BeanFactoryUtils.getOptionalBean; import static org.apache.dubbo.config.spring.util.ObjectUtils.of; +import static org.springframework.util.StringUtils.commaDelimitedListToStringArray; /** * {@link ReferenceBean} Builder @@ -40,6 +42,8 @@ */ class ReferenceBeanBuilder extends AbstractAnnotationConfigBeanBuilder { + // Ignore those fields + static final String[] IGNORE_FIELD_NAMES = of("application", "module", "consumer", "monitor", "registry"); private ReferenceBeanBuilder(Reference annotation, ClassLoader classLoader, ApplicationContext applicationContext) { super(annotation, classLoader, applicationContext); @@ -94,20 +98,30 @@ protected ReferenceBean doBuild() { protected void preConfigureBean(Reference reference, ReferenceBean referenceBean) { Assert.notNull(interfaceClass, "The interface class must set first!"); DataBinder dataBinder = new DataBinder(referenceBean); - // Set ConversionService - dataBinder.setConversionService(getConversionService()); - // Ignore those fields - String[] ignoreAttributeNames = of("application", "module", "consumer", "monitor", "registry"); -// dataBinder.setDisallowedFields(ignoreAttributeNames); + // Register CustomEditors for special fields + dataBinder.registerCustomEditor(String.class, "filter", new StringTrimmerEditor(true)); + dataBinder.registerCustomEditor(String.class, "listener", new StringTrimmerEditor(true)); + dataBinder.registerCustomEditor(Map.class, "parameters", new PropertyEditorSupport() { + + public void setAsText(String text) throws java.lang.IllegalArgumentException { + // Trim all whitespace + String content = StringUtils.trimAllWhitespace(text); + if (!StringUtils.hasText(content)) { // No content , ignore directly + return; + } + // replace "=" to "," + content = StringUtils.replace(content, "=", ","); + // replace ":" to "," + content = StringUtils.replace(content, ":", ","); + // String[] to Map + Map parameters = CollectionUtils.toStringMap(commaDelimitedListToStringArray(content)); + setValue(parameters); + } + }); + // Bind annotation attributes - dataBinder.bind(new AnnotationPropertyValuesAdapter(reference, applicationContext.getEnvironment(), ignoreAttributeNames)); - } + dataBinder.bind(new AnnotationPropertyValuesAdapter(reference, applicationContext.getEnvironment(), IGNORE_FIELD_NAMES)); - private ConversionService getConversionService() { - DefaultConversionService conversionService = new DefaultConversionService(); - conversionService.addConverter(new StringArrayToStringConverter()); - conversionService.addConverter(new StringArrayToMapConverter()); - return conversionService; } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/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 37fed800348..edb0979fcf2 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 @@ -72,7 +72,6 @@ public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, ResourceLoaderAware, BeanClassLoaderAware { - private static final String SEPARATOR = ":"; private final Logger logger = LoggerFactory.getLogger(getClass()); @@ -208,7 +207,7 @@ private BeanNameGenerator resolveBeanNameGenerator(BeanDefinitionRegistry regist * {@link Service} Annotation. * * @param scanner {@link ClassPathBeanDefinitionScanner} - * @param packageToScan package to scan + * @param packageToScan pachage to scan * @param registry {@link BeanDefinitionRegistry} * @return non-null * @since 2.5.8 @@ -262,8 +261,8 @@ private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, Bean if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean registry.registerBeanDefinition(beanName, serviceBeanDefinition); - if (logger.isWarnEnabled()) { - logger.warn("The BeanDefinition[" + serviceBeanDefinition + + if (logger.isInfoEnabled()) { + logger.info("The BeanDefinition[" + serviceBeanDefinition + "] of ServiceBean has been registered with name : " + beanName); } @@ -290,27 +289,10 @@ private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, Bean */ private String generateServiceBeanName(Service service, Class interfaceClass, String annotatedServiceBeanName) { - StringBuilder beanNameBuilder = new StringBuilder(ServiceBean.class.getSimpleName()); - - beanNameBuilder.append(SEPARATOR).append(annotatedServiceBeanName); - - String interfaceClassName = interfaceClass.getName(); - - beanNameBuilder.append(SEPARATOR).append(interfaceClassName); + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, interfaceClass, environment); - String version = service.version(); - - if (StringUtils.hasText(version)) { - beanNameBuilder.append(SEPARATOR).append(version); - } - - String group = service.group(); - - if (StringUtils.hasText(group)) { - beanNameBuilder.append(SEPARATOR).append(group); - } - return beanNameBuilder.toString(); + return builder.build(); } @@ -387,7 +369,8 @@ private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class MutablePropertyValues propertyValues = beanDefinition.getPropertyValues(); - String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol", "interface", "interfaceName"); + String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol", + "interface", "interfaceName"); propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(service, environment, ignoreAttributeNames)); @@ -397,7 +380,7 @@ private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class builder.addPropertyValue("interface", interfaceClass.getName()); /** - * Add {@link org.apache.dubbo.config.ProviderConfig} Bean reference + * Add {@link com.alibaba.dubbo.config.ProviderConfig} Bean reference */ String providerConfigBeanName = service.provider(); if (StringUtils.hasText(providerConfigBeanName)) { @@ -405,7 +388,7 @@ private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class } /** - * Add {@link org.apache.dubbo.config.MonitorConfig} Bean reference + * Add {@link com.alibaba.dubbo.config.MonitorConfig} Bean reference */ String monitorConfigBeanName = service.monitor(); if (StringUtils.hasText(monitorConfigBeanName)) { @@ -413,7 +396,7 @@ private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class } /** - * Add {@link org.apache.dubbo.config.ApplicationConfig} Bean reference + * Add {@link com.alibaba.dubbo.config.ApplicationConfig} Bean reference */ String applicationConfigBeanName = service.application(); if (StringUtils.hasText(applicationConfigBeanName)) { @@ -421,7 +404,7 @@ private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class } /** - * Add {@link org.apache.dubbo.config.ModuleConfig} Bean reference + * Add {@link com.alibaba.dubbo.config.ModuleConfig} Bean reference */ String moduleConfigBeanName = service.module(); if (StringUtils.hasText(moduleConfigBeanName)) { @@ -430,7 +413,7 @@ private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class /** - * Add {@link org.apache.dubbo.config.RegistryConfig} Bean reference + * Add {@link com.alibaba.dubbo.config.RegistryConfig} Bean reference */ String[] registryConfigBeanNames = service.registry(); @@ -441,7 +424,7 @@ private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class } /** - * Add {@link org.apache.dubbo.config.ProtocolConfig} Bean reference + * Add {@link com.alibaba.dubbo.config.ProtocolConfig} Bean reference */ String[] protocolConfigBeanNames = service.protocol(); 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 new file mode 100644 index 00000000000..6cd712408be --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java @@ -0,0 +1,113 @@ +/* + * 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/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 52ab0e67129..e797e5585ec 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 @@ -86,7 +86,7 @@ private void registerDubboConfigBeans(String prefix, boolean multiple, BeanDefinitionRegistry registry) { - Map properties = getSubProperties(environment.getPropertySources(), prefix); + Map properties = getSubProperties(environment.getPropertySources(), prefix); if (CollectionUtils.isEmpty(properties)) { if (log.isDebugEnabled()) { @@ -158,7 +158,7 @@ public void setEnvironment(Environment environment) { } - private Set resolveMultipleBeanNames(Map properties) { + private Set resolveMultipleBeanNames(Map properties) { Set beanNames = new LinkedHashSet(); @@ -179,10 +179,10 @@ private Set resolveMultipleBeanNames(Map properties) { } - private String resolveSingleBeanName(Map properties, Class configClass, + private String resolveSingleBeanName(Map properties, Class configClass, BeanDefinitionRegistry registry) { - String beanName = properties.get("id"); + String beanName = (String) properties.get("id"); if (!StringUtils.hasText(beanName)) { BeanDefinitionBuilder builder = rootBeanDefinition(configClass); diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfiguration.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfiguration.java index de60b5d2cfa..3c5a43f0227 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfiguration.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfiguration.java @@ -26,6 +26,7 @@ import org.apache.dubbo.config.ProviderConfig; import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.spring.ConfigCenterBean; + import org.springframework.context.annotation.Configuration; /** diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java similarity index 66% rename from dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java rename to dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java index 639ad971b4d..cc5f4f8c722 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java @@ -18,22 +18,26 @@ import org.apache.dubbo.config.AbstractConfig; -import org.springframework.context.annotation.ImportSelector; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; +import static org.apache.dubbo.config.spring.util.AnnotatedBeanDefinitionRegistryUtils.registerBeans; + /** - * Dubbo {@link AbstractConfig Config} Registrar + * Dubbo {@link AbstractConfig Config} {@link ImportBeanDefinitionRegistrar register}, which order can be configured * * @see EnableDubboConfig * @see DubboConfigConfiguration + * @see Ordered * @since 2.5.8 */ -public class DubboConfigConfigurationSelector implements ImportSelector, Ordered { +public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar { @Override - public String[] selectImports(AnnotationMetadata importingClassMetadata) { + public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AnnotationAttributes attributes = AnnotationAttributes.fromMap( importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName())); @@ -41,20 +45,10 @@ public String[] selectImports(AnnotationMetadata importingClassMetadata) { boolean multiple = attributes.getBoolean("multiple"); if (multiple) { - return of(DubboConfigConfiguration.Multiple.class.getName()); + registerBeans(registry, DubboConfigConfiguration.Multiple.class); } else { - return of(DubboConfigConfiguration.Single.class.getName()); + registerBeans(registry, DubboConfigConfiguration.Single.class); } } - private static T[] of(T... values) { - return values; - } - - @Override - public int getOrder() { - return HIGHEST_PRECEDENCE; - } - - } 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 889e39078b0..47bafa53b54 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 @@ -66,7 +66,7 @@ @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented -@Import(DubboConfigConfigurationSelector.class) +@Import(DubboConfigConfigurationRegistrar.class) public @interface EnableDubboConfig { /** diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigBinding.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigBinding.java index 8b50f367286..54fc3373eac 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigBinding.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigBinding.java @@ -27,6 +27,7 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -48,6 +49,7 @@ @Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented +@Repeatable(EnableDubboConfigBindings.class) @Import(DubboConfigBindingRegistrar.class) public @interface EnableDubboConfigBinding { diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/event/ServiceBeanExportedEvent.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/event/ServiceBeanExportedEvent.java new file mode 100644 index 00000000000..93c950dfcde --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/event/ServiceBeanExportedEvent.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.config.spring.context.event; + +import org.apache.dubbo.config.spring.ServiceBean; + +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; + +/** + * A {@link ApplicationEvent} after {@link ServiceBean} {@link ServiceBean#export() export} invocation + * + * @see ApplicationEvent + * @see ApplicationListener + * @see ServiceBean + * @since 2.6.5 + */ +public class ServiceBeanExportedEvent extends ApplicationEvent { + + /** + * Create a new ApplicationEvent. + * + * @param serviceBean {@link ServiceBean} bean + */ + public ServiceBeanExportedEvent(ServiceBean serviceBean) { + super(serviceBean); + } + + /** + * Get {@link ServiceBean} instance + * + * @return non-null + */ + public ServiceBean getServiceBean() { + return (ServiceBean) super.getSource(); + } +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java index e1d44da8f7f..ca10d3eb537 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java @@ -37,7 +37,7 @@ public void bind(String prefix, C dubboConfig) { dataBinder.setIgnoreInvalidFields(isIgnoreInvalidFields()); dataBinder.setIgnoreUnknownFields(isIgnoreUnknownFields()); // Get properties under specified prefix from PropertySources - Map properties = getSubProperties(getPropertySources(), prefix); + Map properties = getSubProperties(getPropertySources(), prefix); // Convert Map to MutablePropertyValues MutablePropertyValues propertyValues = new MutablePropertyValues(properties); // Bind @@ -45,3 +45,4 @@ public void bind(String prefix, C dubboConfig) { } } + diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtils.java new file mode 100644 index 00000000000..bf065f8b085 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtils.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.config.spring.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; +import org.springframework.util.ObjectUtils; + +import java.lang.annotation.Annotation; +import java.util.Arrays; + +/** + * Annotated {@link BeanDefinition} Utilities + *

+ * The source code is cloned from https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/AnnotatedBeanDefinitionRegistryUtils.java + * @since 2.6.6 + */ +public abstract class AnnotatedBeanDefinitionRegistryUtils { + + private static final Log logger = LogFactory.getLog(AnnotatedBeanDefinitionRegistryUtils.class); + + /** + * Register Beans + * + * @param registry {@link BeanDefinitionRegistry} + * @param annotatedClasses {@link Annotation annotation} class + */ + public static void registerBeans(BeanDefinitionRegistry registry, Class... annotatedClasses) { + + if (ObjectUtils.isEmpty(annotatedClasses)) { + return; + } + + boolean debugEnabled = logger.isDebugEnabled(); + + AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry); + + if (debugEnabled) { + logger.debug(registry.getClass().getSimpleName() + " will register annotated classes : " + Arrays.asList(annotatedClasses) + " ."); + } + + reader.register(annotatedClasses); + + } +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/AnnotationUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/AnnotationUtils.java index 70c04ccb436..ed2a607bffe 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/AnnotationUtils.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/AnnotationUtils.java @@ -16,20 +16,34 @@ */ package org.apache.dubbo.config.spring.util; +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.annotation.Service; + +import org.springframework.core.env.Environment; import org.springframework.core.env.PropertyResolver; +import org.springframework.util.StringUtils; import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Method; +import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Set; import static java.lang.String.valueOf; +import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes; import static org.springframework.core.annotation.AnnotationUtils.getDefaultValue; import static org.springframework.util.CollectionUtils.arrayToList; import static org.springframework.util.ObjectUtils.nullSafeEquals; -import static org.springframework.util.StringUtils.trimAllWhitespace; +import static org.springframework.util.StringUtils.trimWhitespace; /** * Annotation Utilities Class @@ -39,13 +53,186 @@ */ public class AnnotationUtils { + public static String resolveInterfaceName(Service service, Class defaultInterfaceClass) + throws IllegalStateException { + + String interfaceName; + if (StringUtils.hasText(service.interfaceName())) { + interfaceName = service.interfaceName(); + } else if (!void.class.equals(service.interfaceClass())) { + interfaceName = service.interfaceClass().getName(); + } else if (defaultInterfaceClass.isInterface()) { + interfaceName = defaultInterfaceClass.getName(); + } else { + throw new IllegalStateException( + "The @Service undefined interfaceClass or interfaceName, and the type " + + defaultInterfaceClass.getName() + " is not a interface."); + } + + return interfaceName; + + } + + public static String resolveInterfaceName(Reference reference, Class defaultInterfaceClass) + throws IllegalStateException { + + String interfaceName; + if (!"".equals(reference.interfaceName())) { + interfaceName = reference.interfaceName(); + } else if (!void.class.equals(reference.interfaceClass())) { + interfaceName = reference.interfaceClass().getName(); + } else if (defaultInterfaceClass.isInterface()) { + interfaceName = defaultInterfaceClass.getName(); + } else { + throw new IllegalStateException( + "The @Reference undefined interfaceClass or interfaceName, and the type " + + defaultInterfaceClass.getName() + " is not a interface."); + } + + return interfaceName; + + } + + + // Cloned from https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/AnnotationUtils.java + /** - * Get {@link Annotation} attributes + * Is specified {@link Annotation} present on {@link Method}'s declaring class or parameters or itself. * - * @param annotation - * @param propertyResolver - * @param ignoreDefaultValue + * @param method {@link Method} + * @param annotationClass {@link Annotation} type + * @param {@link Annotation} type + * @return If present , return true , or false + * @since 2.6.6 + */ + public static boolean isPresent(Method method, Class annotationClass) { + + Map> annotationsMap = findAnnotations(method, annotationClass); + + return !annotationsMap.isEmpty(); + + } + + /** + * Find specified {@link Annotation} type maps from {@link Method} + * + * @param method {@link Method} + * @param annotationClass {@link Annotation} type + * @param {@link Annotation} type + * @return {@link Annotation} type maps , the {@link ElementType} as key , + * the list of {@link Annotation} as value. + * If {@link Annotation} was annotated on {@link Method}'s parameters{@link ElementType#PARAMETER} , + * the associated {@link Annotation} list may contain multiple elements. + * @since 2.6.6 + */ + public static Map> findAnnotations(Method method, + Class annotationClass) { + + Retention retention = annotationClass.getAnnotation(Retention.class); + + RetentionPolicy retentionPolicy = retention.value(); + + if (!RetentionPolicy.RUNTIME.equals(retentionPolicy)) { + return Collections.emptyMap(); + } + + Map> annotationsMap = new LinkedHashMap>(); + + Target target = annotationClass.getAnnotation(Target.class); + + ElementType[] elementTypes = target.value(); + + + for (ElementType elementType : elementTypes) { + + List annotationsList = new LinkedList(); + + switch (elementType) { + + case PARAMETER: + + Annotation[][] parameterAnnotations = method.getParameterAnnotations(); + + for (Annotation[] annotations : parameterAnnotations) { + + for (Annotation annotation : annotations) { + + if (annotationClass.equals(annotation.annotationType())) { + + annotationsList.add((A) annotation); + + } + + } + + } + + break; + + case METHOD: + + A annotation = findAnnotation(method, annotationClass); + + if (annotation != null) { + + annotationsList.add(annotation); + + } + + break; + + case TYPE: + + Class beanType = method.getDeclaringClass(); + + A annotation2 = findAnnotation(beanType, annotationClass); + + if (annotation2 != null) { + + annotationsList.add(annotation2); + + } + + break; + + } + + if (!annotationsList.isEmpty()) { + + annotationsMap.put(elementType, annotationsList); + + } + + + } + + return Collections.unmodifiableMap(annotationsMap); + + } + + /** + * Get the {@link Annotation} attributes + * + * @param annotation specified {@link Annotation} + * @param ignoreDefaultValue whether ignore default value or not + * @param ignoreAttributeNames the attribute names of annotation should be ignored * @return non-null + * @since 2.6.6 + */ + public static Map getAttributes(Annotation annotation, boolean ignoreDefaultValue, + String... ignoreAttributeNames) { + return getAttributes(annotation, null, ignoreDefaultValue, ignoreAttributeNames); + } + + /** + * Get the {@link Annotation} attributes + * + * @param annotation specified {@link Annotation} + * @param propertyResolver {@link PropertyResolver} instance, e.g {@link Environment} + * @param ignoreDefaultValue whether ignore default value or not + * @param ignoreAttributeNames the attribute names of annotation should be ignored + * @return non-null + * @since 2.6.6 */ public static Map getAttributes(Annotation annotation, PropertyResolver propertyResolver, boolean ignoreDefaultValue, String... ignoreAttributeNames) { @@ -56,8 +243,6 @@ public static Map getAttributes(Annotation annotation, PropertyR Map actualAttributes = new LinkedHashMap(); - boolean requiredResolve = propertyResolver != null; - for (Map.Entry entry : attributes.entrySet()) { String attributeName = entry.getKey(); @@ -73,17 +258,27 @@ public static Map getAttributes(Annotation annotation, PropertyR continue; } - if (requiredResolve && attributeValue instanceof String) { // Resolve Placeholder - String resolvedValue = propertyResolver.resolvePlaceholders(valueOf(attributeValue)); - attributeValue = trimAllWhitespace(resolvedValue); + if (attributeValue instanceof String) { + attributeValue = resolvePlaceholders(valueOf(attributeValue), propertyResolver); + } else if (attributeValue instanceof String[]) { + String[] values = (String[]) attributeValue; + for (int i = 0; i < values.length; i++) { + values[i] = resolvePlaceholders(values[i], propertyResolver); + } + attributeValue = values; } - actualAttributes.put(attributeName, attributeValue); - } - return actualAttributes; + } + private static String resolvePlaceholders(String attributeValue, PropertyResolver propertyResolver) { + String resolvedValue = attributeValue; + if (propertyResolver != null) { + resolvedValue = propertyResolver.resolvePlaceholders(resolvedValue); + resolvedValue = trimWhitespace(resolvedValue); + } + return resolvedValue; } -} +} \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/BeanFactoryUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/BeanFactoryUtils.java index e519cdee280..71fb7676f88 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/BeanFactoryUtils.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/BeanFactoryUtils.java @@ -16,8 +16,6 @@ */ package org.apache.dubbo.config.spring.util; -import org.apache.dubbo.common.utils.StringUtils; - import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory; @@ -33,6 +31,7 @@ import static org.springframework.beans.factory.BeanFactoryUtils.beanNamesForTypeIncludingAncestors; import static org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors; +import static org.springframework.util.ObjectUtils.containsElement; /** * {@link BeanFactory} Utilities class @@ -44,6 +43,29 @@ */ public class BeanFactoryUtils { + public static boolean addApplicationListener(ApplicationContext applicationContext, ApplicationListener listener) { + try { + // backward compatibility to spring 2.0.1 + Method method = applicationContext.getClass().getMethod("addApplicationListener", ApplicationListener.class); + method.invoke(applicationContext, listener); + return true; + } catch (Throwable t) { + if (applicationContext instanceof AbstractApplicationContext) { + try { + // backward compatibility to spring 2.0.1 + Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", ApplicationListener.class); + if (!method.isAccessible()) { + method.setAccessible(true); + } + method.invoke(applicationContext, listener); + return true; + } catch (Throwable t2) { + // ignore + } + } + } + return false; + } /** * Get optional Bean @@ -53,12 +75,13 @@ public class BeanFactoryUtils { * @param beanType the {@link Class type} of Bean * @param the {@link Class type} of Bean * @return A bean if present , or null + * @since 2.6.6 */ public static T getOptionalBean(ListableBeanFactory beanFactory, String beanName, Class beanType) { String[] allBeanNames = beanNamesForTypeIncludingAncestors(beanFactory, beanType); - if (!StringUtils.isContains(allBeanNames, beanName)) { + if (!containsElement(allBeanNames, beanName)) { return null; } @@ -76,7 +99,8 @@ public static T getOptionalBean(ListableBeanFactory beanFactory, String bean * @param beanNames the names of Bean * @param beanType the {@link Class type} of Bean * @param the {@link Class type} of Bean - * @return + * @return the read-only and non-null {@link List} of Bean names + * @since 2.6.6 */ public static List getBeans(ListableBeanFactory beanFactory, String[] beanNames, Class beanType) { @@ -85,36 +109,11 @@ public static List getBeans(ListableBeanFactory beanFactory, String[] bea List beans = new ArrayList(beanNames.length); for (String beanName : beanNames) { - if (StringUtils.isContains(allBeanNames, beanName)) { + if (containsElement(allBeanNames, beanName)) { beans.add(beanFactory.getBean(beanName, beanType)); } } return Collections.unmodifiableList(beans); - - } - - public static boolean addApplicationListener(ApplicationContext applicationContext, ApplicationListener listener) { - try { - // backward compatibility to spring 2.0.1 - Method method = applicationContext.getClass().getMethod("addApplicationListener", ApplicationListener.class); - method.invoke(applicationContext, listener); - return true; - } catch (Throwable t) { - if (applicationContext instanceof AbstractApplicationContext) { - try { - // backward compatibility to spring 2.0.1 - Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", ApplicationListener.class); - if (!method.isAccessible()) { - method.setAccessible(true); - } - method.invoke(applicationContext, listener); - return true; - } catch (Throwable t2) { - // ignore - } - } - } - return false; } } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToStringConverterTest.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/ClassUtils.java similarity index 55% rename from dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToStringConverterTest.java rename to dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/ClassUtils.java index 83fd804f228..29cd6378748 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToStringConverterTest.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/ClassUtils.java @@ -14,33 +14,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.config.spring.convert.converter; +package org.apache.dubbo.config.spring.util; -import org.junit.Assert; -import org.junit.Test; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; /** - * {@link StringArrayToStringConverter} Test + * {@link Class} Utilities + *

+ * The source code is cloned from + * https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/ClassUtils.java + * + * @since 2.6.6 */ -public 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); +public abstract class ClassUtils { + public static Class resolveGenericType(Class declaredClass) { + ParameterizedType parameterizedType = (ParameterizedType) declaredClass.getGenericSuperclass(); + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + return (Class) actualTypeArguments[0]; } - } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/ObjectUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/ObjectUtils.java index 0ffd7a77a5d..57832cc926b 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/ObjectUtils.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/ObjectUtils.java @@ -17,18 +17,18 @@ package org.apache.dubbo.config.spring.util; /** - * Object Utilities Class + * Object Utilities * - * @since 2.5.11 + * @since 2.6.6 */ -public class ObjectUtils { +public abstract class ObjectUtils { /** - * of factory method + * Convert from variable arguments to array * - * @param values - * @param - * @return + * @param values variable arguments + * @param The class + * @return array */ public static T[] of(T... values) { return values; diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/PropertySourcesUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/PropertySourcesUtils.java index 28d43fc2179..8a070579b34 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/PropertySourcesUtils.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/PropertySourcesUtils.java @@ -16,20 +16,25 @@ */ package org.apache.dubbo.config.spring.util; +import org.springframework.core.env.AbstractEnvironment; +import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; import org.springframework.core.env.PropertySources; -import org.springframework.core.env.PropertySourcesPropertyResolver; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import java.util.Properties; + /** * {@link PropertySources} Utilities + *

+ * The source code is cloned from https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/PropertySourcesUtils.java * - * @see PropertySources - * @since 2.5.8 + * @since 2.6.6 */ public abstract class PropertySourcesUtils { @@ -38,30 +43,60 @@ public abstract class PropertySourcesUtils { * * @param propertySources {@link PropertySource} Iterable * @param prefix the prefix of property name - * @return Map + * @return Map * @see Properties */ - public static Map getSubProperties(Iterable> propertySources, String prefix) { + public static Map getSubProperties(Iterable> propertySources, String prefix) { - Map subProperties = new LinkedHashMap(); + // Non-Extension AbstractEnvironment + AbstractEnvironment environment = new AbstractEnvironment() { + }; - String normalizedPrefix = normalizePrefix(prefix); + MutablePropertySources mutablePropertySources = environment.getPropertySources(); + + for (PropertySource source : propertySources) { + mutablePropertySources.addLast(source); + } + + return getSubProperties(environment, prefix); + + } + + /** + * Get Sub {@link Properties} + * + * @param environment {@link ConfigurableEnvironment} + * @param prefix the prefix of property name + * @return Map + * @see Properties + */ + public static Map getSubProperties(ConfigurableEnvironment environment, String prefix) { - PropertySourcesPropertyResolver propertyResolver = new PropertySourcesPropertyResolver((PropertySources) propertySources); + Map subProperties = new LinkedHashMap(); + + MutablePropertySources propertySources = environment.getPropertySources(); + + String normalizedPrefix = normalizePrefix(prefix); for (PropertySource source : propertySources) { if (source instanceof EnumerablePropertySource) { for (String name : ((EnumerablePropertySource) source).getPropertyNames()) { - if (name.startsWith(normalizedPrefix)) { + if (!subProperties.containsKey(name) && name.startsWith(normalizedPrefix)) { String subName = name.substring(normalizedPrefix.length()); - String value = propertyResolver.getProperty(name); - subProperties.putIfAbsent(subName, value); + if (!subProperties.containsKey(subName)) { // take first one + Object value = source.getProperty(name); + if (value instanceof String) { + // Resolve placeholder + value = environment.resolvePlaceholders((String) value); + } + subProperties.put(subName, value); + } } } } } - return subProperties; + return Collections.unmodifiableMap(subProperties); } @@ -74,5 +109,4 @@ public static Map getSubProperties(Iterable> p public static String normalizePrefix(String prefix) { return prefix.endsWith(".") ? prefix : prefix + "."; } - } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ConfigTest.java index d68a2952968..acd75bf98a1 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ConfigTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ConfigTest.java @@ -1,1021 +1,1022 @@ -/* - * 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; - -import org.apache.dubbo.common.Constants; -import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.extension.ExtensionLoader; -import org.apache.dubbo.common.utils.NetUtils; -import org.apache.dubbo.common.utils.StringUtils; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ConsumerConfig; -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.ProviderConfig; -import org.apache.dubbo.config.ReferenceConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ServiceConfig; -import org.apache.dubbo.config.spring.action.DemoActionByAnnotation; -import org.apache.dubbo.config.spring.action.DemoActionBySetter; -import org.apache.dubbo.config.spring.annotation.consumer.AnnotationAction; -import org.apache.dubbo.config.spring.api.DemoService; -import org.apache.dubbo.config.spring.api.HelloService; -import org.apache.dubbo.config.spring.context.annotation.provider.ProviderConfiguration; -import org.apache.dubbo.config.spring.filter.MockFilter; -import org.apache.dubbo.config.spring.impl.DemoServiceImpl; -import org.apache.dubbo.config.spring.impl.HelloServiceImpl; -import org.apache.dubbo.config.spring.registry.MockRegistry; -import org.apache.dubbo.config.spring.registry.MockRegistryFactory; -import org.apache.dubbo.registry.Registry; -import org.apache.dubbo.registry.RegistryService; -import org.apache.dubbo.rpc.Exporter; -import org.apache.dubbo.rpc.Filter; -import org.apache.dubbo.rpc.RpcContext; -import org.apache.dubbo.rpc.RpcException; -import org.apache.dubbo.rpc.service.GenericException; -import org.apache.dubbo.rpc.service.GenericService; -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.util.Collection; -import java.util.List; - -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; - - -/** - * ConfigTest - */ -@Ignore -public class ConfigTest { - - private static void unexportService(ServiceConfig config) { - if (config != null) { - config.unexport(); - } - } - - @Test - public void testSpringExtensionInject() { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/spring-extension-inject.xml"); - ctx.start(); - try { - MockFilter filter = (MockFilter) ExtensionLoader.getExtensionLoader(Filter.class).getExtension("mymock"); - assertNotNull(filter.getMockDao()); - assertNotNull(filter.getProtocol()); - assertNotNull(filter.getLoadBalance()); - } finally { - ctx.stop(); - ctx.close(); - } - } - - @Test - public void testServiceClass() { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/service-class.xml"); - ctx.start(); - try { - DemoService demoService = refer("dubbo://127.0.0.1:30887"); - String hello = demoService.sayName("hello"); - assertEquals("welcome:hello", hello); - } finally { - ctx.stop(); - ctx.close(); - } - } - - @Test - public void testServiceAnnotation() { - AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext(); - providerContext.register(ProviderConfiguration.class); - - providerContext.refresh(); - - ReferenceConfig reference = new ReferenceConfig(); - reference.setApplication(new ApplicationConfig("consumer")); - reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); - reference.setInterface(HelloService.class); - reference.setUrl("dubbo://127.0.0.1:12345"); - String hello = reference.get().sayHello("hello"); - assertEquals("Hello, hello", hello); - - } - - @Test - @SuppressWarnings("unchecked") - public void testProviderNestedService() { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/provider-nested-service.xml"); - ctx.start(); - try { - ServiceConfig serviceConfig = (ServiceConfig) ctx.getBean("serviceConfig"); - assertNotNull(serviceConfig.getProvider()); - assertEquals(2000, serviceConfig.getProvider().getTimeout().intValue()); - - ServiceConfig serviceConfig2 = (ServiceConfig) ctx.getBean("serviceConfig2"); - assertNotNull(serviceConfig2.getProvider()); - assertEquals(1000, serviceConfig2.getProvider().getTimeout().intValue()); - } finally { - ctx.stop(); - ctx.close(); - } - } - - private DemoService refer(String url) { - ReferenceConfig reference = new ReferenceConfig(); - reference.setApplication(new ApplicationConfig("consumer")); - reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); - reference.setInterface(DemoService.class); - reference.setUrl(url); - return reference.get(); - } - - @Test - public void testToString() { - ReferenceConfig reference = new ReferenceConfig(); - reference.setApplication(new ApplicationConfig("consumer")); - reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); - reference.setInterface(DemoService.class); - reference.setUrl("dubbo://127.0.0.1:20881"); - String str = reference.toString(); - assertTrue(str.startsWith("")); - } - - @Test - public void testForks() { - ReferenceConfig reference = new ReferenceConfig(); - reference.setApplication(new ApplicationConfig("consumer")); - reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); - reference.setInterface(DemoService.class); - reference.setUrl("dubbo://127.0.0.1:20881"); - - int forks = 10; - reference.setForks(forks); - String str = reference.toString(); - assertTrue(str.contains("forks=\"" + forks + "\"")); - } - - @Test - public void testMultiProtocol() { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-protocol.xml"); - ctx.start(); - try { - DemoService demoService = refer("dubbo://127.0.0.1:20881"); - String hello = demoService.sayName("hello"); - assertEquals("say:hello", hello); - } finally { - ctx.stop(); - ctx.close(); - } - } - - @Test - public void testMultiProtocolDefault() { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-protocol-default.xml"); - ctx.start(); - try { - DemoService demoService = refer("rmi://127.0.0.1:10991"); - String hello = demoService.sayName("hello"); - assertEquals("say:hello", hello); - } finally { - ctx.stop(); - ctx.close(); - } - } - - @Test - public void testMultiProtocolError() { - try { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-protocol-error.xml"); - ctx.start(); - ctx.stop(); - ctx.close(); - } catch (BeanCreationException e) { - assertTrue(e.getMessage().contains("Found multi-protocols")); - } - } - - @Test - public void testMultiProtocolRegister() { - SimpleRegistryService registryService = new SimpleRegistryService(); - Exporter exporter = SimpleRegistryExporter.export(4547, registryService); - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-protocol-register.xml"); - ctx.start(); - try { - List urls = registryService.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); - assertNotNull(urls); - assertEquals(1, urls.size()); - assertEquals("dubbo://" + NetUtils.getLocalHost() + ":20824/org.apache.dubbo.config.spring.api.DemoService", urls.get(0).toIdentityString()); - } finally { - ctx.stop(); - ctx.close(); - exporter.unexport(); - } - } - - @Test - public void testMultiRegistry() { - SimpleRegistryService registryService1 = new SimpleRegistryService(); - Exporter exporter1 = SimpleRegistryExporter.export(4545, registryService1); - SimpleRegistryService registryService2 = new SimpleRegistryService(); - Exporter exporter2 = SimpleRegistryExporter.export(4546, registryService2); - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-registry.xml"); - ctx.start(); - try { - List urls1 = registryService1.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); - assertNull(urls1); - List urls2 = registryService2.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); - assertNotNull(urls2); - assertEquals(1, urls2.size()); - assertEquals("dubbo://" + NetUtils.getLocalHost() + ":20880/org.apache.dubbo.config.spring.api.DemoService", urls2.get(0).toIdentityString()); - } finally { - ctx.stop(); - ctx.close(); - exporter1.unexport(); - exporter2.unexport(); - } - } - - @Test - public void testDelayFixedTime() throws Exception { - SimpleRegistryService registryService = new SimpleRegistryService(); - Exporter exporter = SimpleRegistryExporter.export(4548, registryService); - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/delay-fixed-time.xml"); - ctx.start(); - try { - List urls = registryService.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); - assertNull(urls); - int i = 0; - while ((i++) < 60 && urls == null) { - urls = registryService.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); - Thread.sleep(10); - } - assertNotNull(urls); - assertEquals(1, urls.size()); - assertEquals("dubbo://" + NetUtils.getLocalHost() + ":20888/org.apache.dubbo.config.spring.api.DemoService", urls.get(0).toIdentityString()); - } finally { - ctx.stop(); - ctx.close(); - exporter.unexport(); - } - } - - @Test - public void testDelayOnInitialized() throws Exception { - SimpleRegistryService registryService = new SimpleRegistryService(); - Exporter exporter = SimpleRegistryExporter.export(4548, registryService); - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/delay-on-initialized.xml"); - //ctx.start(); - try { - List urls = registryService.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); - assertNotNull(urls); - assertEquals(1, urls.size()); - assertEquals("dubbo://" + NetUtils.getLocalHost() + ":20888/org.apache.dubbo.config.spring.api.DemoService", urls.get(0).toIdentityString()); - } finally { - ctx.stop(); - ctx.close(); - exporter.unexport(); - } - } - - @Test - public void testRmiTimeout() throws Exception { - if (System.getProperty("sun.rmi.transport.tcp.responseTimeout") != null) { - System.setProperty("sun.rmi.transport.tcp.responseTimeout", ""); - } - ConsumerConfig consumer = new ConsumerConfig(); - consumer.setTimeout(1000); - assertEquals("1000", System.getProperty("sun.rmi.transport.tcp.responseTimeout")); - consumer.setTimeout(2000); - assertEquals("1000", System.getProperty("sun.rmi.transport.tcp.responseTimeout")); - } - - @Test - public void testAutowireAndAOP() throws Exception { - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider.xml"); - providerContext.start(); - try { - ClassPathXmlApplicationContext byNameContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/aop-autowire-byname.xml"); - byNameContext.start(); - try { - DemoActionBySetter demoActionBySetter = (DemoActionBySetter) byNameContext.getBean("demoActionBySetter"); - assertNotNull(demoActionBySetter.getDemoService()); - assertEquals("aop:say:hello", demoActionBySetter.getDemoService().sayName("hello")); - DemoActionByAnnotation demoActionByAnnotation = (DemoActionByAnnotation) byNameContext.getBean("demoActionByAnnotation"); - assertNotNull(demoActionByAnnotation.getDemoService()); - assertEquals("aop:say:hello", demoActionByAnnotation.getDemoService().sayName("hello")); - } finally { - byNameContext.stop(); - byNameContext.close(); - } - ClassPathXmlApplicationContext byTypeContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/aop-autowire-bytype.xml"); - byTypeContext.start(); - try { - DemoActionBySetter demoActionBySetter = (DemoActionBySetter) byTypeContext.getBean("demoActionBySetter"); - assertNotNull(demoActionBySetter.getDemoService()); - assertEquals("aop:say:hello", demoActionBySetter.getDemoService().sayName("hello")); - DemoActionByAnnotation demoActionByAnnotation = (DemoActionByAnnotation) byTypeContext.getBean("demoActionByAnnotation"); - assertNotNull(demoActionByAnnotation.getDemoService()); - assertEquals("aop:say:hello", demoActionByAnnotation.getDemoService().sayName("hello")); - } finally { - byTypeContext.stop(); - byTypeContext.close(); - } - } finally { - providerContext.stop(); - providerContext.close(); - } - } - - @Test - public void testAppendFilter() throws Exception { - ProviderConfig provider = new ProviderConfig(); - provider.setFilter("classloader,monitor"); - ServiceConfig service = new ServiceConfig(); - service.setFilter("accesslog,trace"); - service.setProvider(provider); - service.setProtocol(new ProtocolConfig("dubbo", 20880)); - service.setApplication(new ApplicationConfig("provider")); - service.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); - service.setInterface(DemoService.class); - service.setRef(new DemoServiceImpl()); - try { - service.export(); - List urls = service.toUrls(); - assertNotNull(urls); - assertEquals(1, urls.size()); - assertEquals("classloader,monitor,accesslog,trace", urls.get(0).getParameter("service.filter")); - - ConsumerConfig consumer = new ConsumerConfig(); - consumer.setFilter("classloader,monitor"); - ReferenceConfig reference = new ReferenceConfig(); - reference.setFilter("accesslog,trace"); - reference.setConsumer(consumer); - reference.setApplication(new ApplicationConfig("consumer")); - reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); - reference.setInterface(DemoService.class); - reference.setUrl("dubbo://" + NetUtils.getLocalHost() + ":20880?" + DemoService.class.getName() + "?check=false"); - try { - reference.get(); - urls = reference.toUrls(); - assertNotNull(urls); - assertEquals(1, urls.size()); - assertEquals("classloader,monitor,accesslog,trace", urls.get(0).getParameter("reference.filter")); - } finally { - reference.destroy(); - } - } finally { - service.unexport(); - } - } - - @Test - public void testInitReference() throws Exception { - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider.xml"); - providerContext.start(); - try { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/init-reference.xml"); - ctx.start(); - try { - DemoService demoService = (DemoService) ctx.getBean("demoService"); - assertEquals("say:world", demoService.sayName("world")); - } finally { - ctx.stop(); - ctx.close(); - } - } finally { - providerContext.stop(); - providerContext.close(); - } - } - - // DUBBO-571 methods key in provider's URLONE doesn't contain the methods from inherited super interface - @Test - public void test_noMethodInterface_methodsKeyHasValue() throws Exception { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider-no-methods-interface.xml"); - ctx.start(); - try { - ServiceBean bean = (ServiceBean) ctx.getBean("service"); - List urls = bean.getExportedUrls(); - assertEquals(1, urls.size()); - URL url = urls.get(0); - assertEquals("sayName,getBox", url.getParameter("methods")); - } finally { - ctx.stop(); - ctx.close(); - } - } - - // DUBBO-147 find all invoker instances which have been tried from RpcContext - @Test - public void test_RpcContext_getUrls() throws Exception { - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext( - ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider-long-waiting.xml"); - providerContext.start(); - - try { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( - ConfigTest.class.getPackage().getName().replace('.', '/') - + "/init-reference-getUrls.xml"); - ctx.start(); - try { - DemoService demoService = (DemoService) ctx.getBean("demoService"); - try { - demoService.sayName("Haha"); - fail(); - } catch (RpcException expected) { - assertThat(expected.getMessage(), containsString("Tried 3 times")); - } - - assertEquals(3, RpcContext.getContext().getUrls().size()); - } finally { - ctx.stop(); - ctx.close(); - } - } finally { - providerContext.stop(); - providerContext.close(); - } - } - - // BUG: DUBBO-846 in version 2.0.9, config retry="false" on provider's method doesn't work - @Test - public void test_retrySettingFail() throws Exception { - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext( - ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider-long-waiting.xml"); - providerContext.start(); - - try { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( - ConfigTest.class.getPackage().getName().replace('.', '/') - + "/init-reference-retry-false.xml"); - ctx.start(); - try { - DemoService demoService = (DemoService) ctx.getBean("demoService"); - try { - demoService.sayName("Haha"); - fail(); - } catch (RpcException expected) { - assertThat(expected.getMessage(), containsString("Tried 1 times")); - } - - assertEquals(1, RpcContext.getContext().getUrls().size()); - } finally { - ctx.stop(); - ctx.close(); - } - } finally { - providerContext.stop(); - providerContext.close(); - } - } - - // BuG: DUBBO-146 Provider doesn't have exception output, and consumer has timeout error when serialization fails - // for example, object transported on the wire doesn't implement Serializable - @Test - public void test_returnSerializationFail() throws Exception { - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider-UnserializableBox.xml"); - providerContext.start(); - try { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/init-reference.xml"); - ctx.start(); - try { - DemoService demoService = (DemoService) ctx.getBean("demoService"); - try { - demoService.getBox(); - fail(); - } catch (RpcException expected) { - assertThat(expected.getMessage(), containsString("must implement java.io.Serializable")); - } - } finally { - ctx.stop(); - ctx.close(); - } - } finally { - providerContext.stop(); - providerContext.close(); - } - } - - @Test - public void testXmlOverrideProperties() throws Exception { - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/xml-override-properties.xml"); - providerContext.start(); - try { - ApplicationConfig application = (ApplicationConfig) providerContext.getBean("application"); - assertEquals("demo-provider", application.getName()); - assertEquals("world", application.getOwner()); - - RegistryConfig registry = (RegistryConfig) providerContext.getBean("registry"); - assertEquals("N/A", registry.getAddress()); - - ProtocolConfig dubbo = (ProtocolConfig) providerContext.getBean("dubbo"); - assertEquals(20813, dubbo.getPort().intValue()); - - } finally { - providerContext.stop(); - providerContext.close(); - } - } - - @Test - public void testApiOverrideProperties() throws Exception { - ApplicationConfig application = new ApplicationConfig(); - application.setName("api-override-properties"); - - RegistryConfig registry = new RegistryConfig(); - registry.setAddress("N/A"); - - ProtocolConfig protocol = new ProtocolConfig(); - protocol.setName("dubbo"); - protocol.setPort(13123); - - ServiceConfig service = new ServiceConfig(); - service.setInterface(DemoService.class); - service.setRef(new DemoServiceImpl()); - service.setApplication(application); - service.setRegistry(registry); - service.setProtocol(protocol); - service.export(); - - try { - URL url = service.toUrls().get(0); - assertEquals("api-override-properties", url.getParameter("application")); - assertEquals("world", url.getParameter("owner")); - assertEquals(13123, url.getPort()); - - ReferenceConfig reference = new ReferenceConfig(); - reference.setApplication(new ApplicationConfig("consumer")); - reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); - reference.setInterface(DemoService.class); - reference.setUrl("dubbo://127.0.0.1:13123"); - reference.get(); - try { - url = reference.toUrls().get(0); - assertEquals("2000", url.getParameter("timeout")); - } finally { - reference.destroy(); - } - } finally { - service.unexport(); - } - } - - @Test - public void testSystemPropertyOverrideProtocol() throws Exception { - System.setProperty("dubbo.protocol.port", "20812"); - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/override-protocol.xml"); - providerContext.start(); - try { - ProtocolConfig dubbo = (ProtocolConfig) providerContext.getBean("dubbo"); - assertEquals(20812, dubbo.getPort().intValue()); - } finally { - System.setProperty("dubbo.protocol.port", ""); - providerContext.stop(); - providerContext.close(); - } - } - - @Test - public void testSystemPropertyOverrideMultiProtocol() throws Exception { - System.setProperty("dubbo.protocol.dubbo.port", "20814"); - System.setProperty("dubbo.protocol.rmi.port", "10914"); - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/override-multi-protocol.xml"); - providerContext.start(); - try { - ProtocolConfig dubbo = (ProtocolConfig) providerContext.getBean("dubbo"); - assertEquals(20814, dubbo.getPort().intValue()); - ProtocolConfig rmi = (ProtocolConfig) providerContext.getBean("rmi"); - assertEquals(10914, rmi.getPort().intValue()); - } finally { - System.setProperty("dubbo.protocol.dubbo.port", ""); - System.setProperty("dubbo.protocol.rmi.port", ""); - providerContext.stop(); - providerContext.close(); - } - } - - @SuppressWarnings("unchecked") - @Test - public void testSystemPropertyOverrideXmlDefault() throws Exception { - System.setProperty("dubbo.application.name", "sysover"); - System.setProperty("dubbo.application.owner", "sysowner"); - System.setProperty("dubbo.registry.address", "N/A"); - System.setProperty("dubbo.protocol.name", "dubbo"); - System.setProperty("dubbo.protocol.port", "20819"); - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/system-properties-override-default.xml"); - providerContext.start(); - try { - ServiceConfig service = (ServiceConfig) providerContext.getBean("demoServiceConfig"); - assertEquals("sysover", service.getApplication().getName()); - assertEquals("sysowner", service.getApplication().getOwner()); - assertEquals("N/A", service.getRegistry().getAddress()); - assertEquals("dubbo", service.getProtocol().getName()); - assertEquals(20819, service.getProtocol().getPort().intValue()); - } finally { - System.setProperty("dubbo.application.name", ""); - System.setProperty("dubbo.application.owner", ""); - System.setProperty("dubbo.registry.address", ""); - System.setProperty("dubbo.protocol.name", ""); - System.setProperty("dubbo.protocol.port", ""); - providerContext.stop(); - providerContext.close(); - } - } - - @SuppressWarnings("unchecked") - @Test - public void testSystemPropertyOverrideXml() throws Exception { - System.setProperty("dubbo.application.name", "sysover"); - System.setProperty("dubbo.application.owner", "sysowner"); - System.setProperty("dubbo.registry.address", "N/A"); - System.setProperty("dubbo.protocol.name", "dubbo"); - System.setProperty("dubbo.protocol.port", "20819"); - System.setProperty("dubbo.service.register", "false"); - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/system-properties-override.xml"); - providerContext.start(); - try { - ServiceConfig service = (ServiceConfig) providerContext.getBean("demoServiceConfig"); - URL url = service.toUrls().get(0); - assertEquals("sysover", url.getParameter("application")); - assertEquals("sysowner", url.getParameter("owner")); - assertEquals("dubbo", url.getProtocol()); - assertEquals(20819, url.getPort()); - String register = url.getParameter("register"); - assertTrue(register != null && !"".equals(register)); - assertEquals(false, Boolean.valueOf(register)); - } finally { - System.setProperty("dubbo.application.name", ""); - System.setProperty("dubbo.application.owner", ""); - System.setProperty("dubbo.registry.address", ""); - System.setProperty("dubbo.protocol.name", ""); - System.setProperty("dubbo.protocol.port", ""); - System.setProperty("dubbo.service.register", ""); - providerContext.stop(); - providerContext.close(); - } - } - - @Test - public void testSystemPropertyOverrideReferenceConfig() throws Exception { - System.setProperty("dubbo.reference.retries", "5"); - - try { - ServiceConfig service = new ServiceConfig(); - service.setInterface(DemoService.class); - service.setRef(new DemoServiceImpl()); - service.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); - ProtocolConfig protocolConfig = new ProtocolConfig("injvm"); - service.setProtocol(protocolConfig); - service.export(); - - ReferenceConfig reference = new ReferenceConfig(); - reference.setInterface(DemoService.class); - reference.setInjvm(true); - reference.setRetries(2); - reference.get(); - assertEquals(Integer.valueOf(5), reference.getRetries()); - } finally { - System.setProperty("dubbo.reference.retries", ""); - } - } - - @Test - public void testSystemPropertyOverrideApiDefault() throws Exception { - System.setProperty("dubbo.application.name", "sysover"); - System.setProperty("dubbo.application.owner", "sysowner"); - System.setProperty("dubbo.registry.address", "N/A"); - System.setProperty("dubbo.protocol.name", "dubbo"); - System.setProperty("dubbo.protocol.port", "20834"); - try { - ServiceConfig serviceConfig = new ServiceConfig(); - serviceConfig.setInterface(DemoService.class); - serviceConfig.setRef(new DemoServiceImpl()); - serviceConfig.export(); - try { - assertEquals("sysover", serviceConfig.getApplication().getName()); - assertEquals("sysowner", serviceConfig.getApplication().getOwner()); - assertEquals("N/A", serviceConfig.getRegistry().getAddress()); - assertEquals("dubbo", serviceConfig.getProtocol().getName()); - assertEquals(20834, serviceConfig.getProtocol().getPort().intValue()); - } finally { - serviceConfig.unexport(); - } - } finally { - System.setProperty("dubbo.application.name", ""); - System.setProperty("dubbo.application.owner", ""); - System.setProperty("dubbo.registry.address", ""); - System.setProperty("dubbo.protocol.name", ""); - System.setProperty("dubbo.protocol.port", ""); - } - } - - @Test - public void testSystemPropertyOverrideApi() throws Exception { - System.setProperty("dubbo.application.name", "sysover"); - System.setProperty("dubbo.application.owner", "sysowner"); - System.setProperty("dubbo.registry.address", "N/A"); - System.setProperty("dubbo.protocol.name", "dubbo"); - System.setProperty("dubbo.protocol.port", "20834"); - try { - ApplicationConfig application = new ApplicationConfig(); - application.setName("aaa"); - - RegistryConfig registry = new RegistryConfig(); - registry.setAddress("127.0.0.1"); - - ProtocolConfig protocol = new ProtocolConfig(); - protocol.setName("rmi"); - protocol.setPort(1099); - - ServiceConfig service = new ServiceConfig(); - service.setInterface(DemoService.class); - service.setRef(new DemoServiceImpl()); - service.setApplication(application); - service.setRegistry(registry); - service.setProtocol(protocol); - service.export(); - - try { - URL url = service.toUrls().get(0); - assertEquals("sysover", url.getParameter("application")); - assertEquals("sysowner", url.getParameter("owner")); - assertEquals("dubbo", url.getProtocol()); - assertEquals(20834, url.getPort()); - } finally { - service.unexport(); - } - } finally { - System.setProperty("dubbo.application.name", ""); - System.setProperty("dubbo.application.owner", ""); - System.setProperty("dubbo.registry.address", ""); - System.setProperty("dubbo.protocol.name", ""); - System.setProperty("dubbo.protocol.port", ""); - } - } - - @Test - public void testSystemPropertyOverrideProperties() throws Exception { - String portString = System.getProperty("dubbo.protocol.port"); - System.clearProperty("dubbo.protocol.port"); - try { - int port = 1234; - System.setProperty("dubbo.protocol.port", String.valueOf(port)); - ApplicationConfig application = new ApplicationConfig(); - application.setName("aaa"); - - RegistryConfig registry = new RegistryConfig(); - registry.setAddress("N/A"); - - ProtocolConfig protocol = new ProtocolConfig(); - protocol.setName("rmi"); - - ServiceConfig service = new ServiceConfig(); - service.setInterface(DemoService.class); - service.setRef(new DemoServiceImpl()); - service.setApplication(application); - service.setRegistry(registry); - service.setProtocol(protocol); - service.export(); - - try { - URL url = service.toUrls().get(0); - // from api - assertEquals("aaa", url.getParameter("application")); - // from dubbo.properties - assertEquals("world", url.getParameter("owner")); - // from system property - assertEquals(1234, url.getPort()); - } finally { - service.unexport(); - } - } finally { - if (portString != null) { - System.setProperty("dubbo.protocol.port", portString); - } - } - } - - @Test - @SuppressWarnings("unchecked") - public void testCustomizeParameter() throws Exception { - ClassPathXmlApplicationContext context = - new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/customize-parameter.xml"); - context.start(); - ServiceBean serviceBean = (ServiceBean) context.getBean("demoServiceExport"); - URL url = (URL) serviceBean.toUrls().get(0); - assertEquals("protocol-paramA", url.getParameter("protocol.paramA")); - assertEquals("service-paramA", url.getParameter("service.paramA")); - } - - @Test - public void testPath() throws Exception { - ServiceConfig service = new ServiceConfig(); - service.setPath("a/b$c"); - try { - service.setPath("a?b"); - fail(); - } catch (IllegalStateException e) { - assertTrue(e.getMessage().contains("")); - } - } - - @Test - public void testAnnotation() { - SimpleRegistryService registryService = new SimpleRegistryService(); - Exporter exporter = SimpleRegistryExporter.export(4548, registryService); - try { - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/annotation-provider.xml"); - providerContext.start(); - try { - ClassPathXmlApplicationContext consumerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/annotation-consumer.xml"); - consumerContext.start(); - try { - AnnotationAction annotationAction = (AnnotationAction) consumerContext.getBean("annotationAction"); - String hello = annotationAction.doSayName("hello"); - assertEquals("annotation:hello", hello); - } finally { - consumerContext.stop(); - consumerContext.close(); - } - } finally { - providerContext.stop(); - providerContext.close(); - } - } finally { - exporter.unexport(); - } - } - - @Test - public void testDubboProtocolPortOverride() throws Exception { - String dubboPort = System.getProperty("dubbo.protocol.dubbo.port"); - int port = 55555; - System.setProperty("dubbo.protocol.dubbo.port", String.valueOf(port)); - ServiceConfig service = null; - try { - ApplicationConfig application = new ApplicationConfig(); - application.setName("dubbo-protocol-port-override"); - - RegistryConfig registry = new RegistryConfig(); - registry.setAddress("N/A"); - - ProtocolConfig protocol = new ProtocolConfig(); - - service = new ServiceConfig(); - service.setInterface(DemoService.class); - service.setRef(new DemoServiceImpl()); - service.setApplication(application); - service.setRegistry(registry); - service.setProtocol(protocol); - service.export(); - - Assert.assertEquals(port, service.getExportedUrls().get(0).getPort()); - } finally { - if (StringUtils.isNotEmpty(dubboPort)) { - System.setProperty("dubbo.protocol.dubbo.port", dubboPort); - } - if (service != null) { - service.unexport(); - } - } - } - - @Test - public void testProtocolRandomPort() throws Exception { - ServiceConfig demoService = null; - ServiceConfig helloService = null; - - ApplicationConfig application = new ApplicationConfig(); - application.setName("test-protocol-random-port"); - - RegistryConfig registry = new RegistryConfig(); - registry.setAddress("N/A"); - - ProtocolConfig protocol = new ProtocolConfig(); - protocol.setName("dubbo"); - protocol.setPort(-1); - - demoService = new ServiceConfig(); - demoService.setInterface(DemoService.class); - demoService.setRef(new DemoServiceImpl()); - demoService.setApplication(application); - demoService.setRegistry(registry); - demoService.setProtocol(protocol); - - helloService = new ServiceConfig(); - helloService.setInterface(HelloService.class); - helloService.setRef(new HelloServiceImpl()); - helloService.setApplication(application); - helloService.setRegistry(registry); - helloService.setProtocol(protocol); - - try { - demoService.export(); - helloService.export(); - - Assert.assertEquals(demoService.getExportedUrls().get(0).getPort(), - helloService.getExportedUrls().get(0).getPort()); - } finally { - unexportService(demoService); - unexportService(helloService); - } - } - - @Test - public void testReferGenericExport() throws Exception { - ApplicationConfig ac = new ApplicationConfig("test-refer-generic-export"); - RegistryConfig rc = new RegistryConfig(); - rc.setAddress(RegistryConfig.NO_AVAILABLE); - - ServiceConfig sc = new ServiceConfig(); - sc.setApplication(ac); - sc.setRegistry(rc); - sc.setInterface(DemoService.class.getName()); - sc.setRef(new GenericService() { - - public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException { - return null; - } - }); - - ReferenceConfig ref = new ReferenceConfig(); - ref.setApplication(ac); - ref.setRegistry(rc); - ref.setInterface(DemoService.class.getName()); - - try { - sc.export(); - ref.get(); - Assert.fail(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - sc.unexport(); - ref.destroy(); - } - } - - @Test - public void testGenericServiceConfig() throws Exception { - ServiceConfig service = new ServiceConfig(); - service.setApplication(new ApplicationConfig("test")); - service.setRegistry(new RegistryConfig("mock://localhost")); - service.setInterface(DemoService.class.getName()); - service.setGeneric(Constants.GENERIC_SERIALIZATION_BEAN); - service.setRef(new GenericService() { - - public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException { - return null; - } - }); - try { - service.export(); - Collection collection = MockRegistryFactory.getCachedRegistry(); - MockRegistry registry = (MockRegistry) collection.iterator().next(); - URL url = registry.getRegistered().get(0); - Assert.assertEquals(Constants.GENERIC_SERIALIZATION_BEAN, url.getParameter(Constants.GENERIC_KEY)); - } finally { - MockRegistryFactory.cleanCachedRegistry(); - service.unexport(); - } - } - - @Test - public void testGenericServiceConfigThroughSpring() throws Exception { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/generic-export.xml"); - try { - ctx.start(); - ServiceConfig serviceConfig = (ServiceConfig) ctx.getBean("dubboDemoService"); - URL url = (URL) serviceConfig.getExportedUrls().get(0); - Assert.assertEquals(Constants.GENERIC_SERIALIZATION_BEAN, url.getParameter(Constants.GENERIC_KEY)); - } finally { - ctx.destroy(); - } - } +/* + * 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; + +import org.apache.dubbo.common.Constants; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.extension.ExtensionLoader; +import org.apache.dubbo.common.utils.NetUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ConsumerConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.ProviderConfig; +import org.apache.dubbo.config.ReferenceConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.ServiceConfig; +import org.apache.dubbo.config.spring.action.DemoActionByAnnotation; +import org.apache.dubbo.config.spring.action.DemoActionBySetter; +import org.apache.dubbo.config.spring.annotation.consumer.AnnotationAction; +import org.apache.dubbo.config.spring.api.DemoService; +import org.apache.dubbo.config.spring.api.HelloService; +import org.apache.dubbo.config.spring.context.annotation.provider.ProviderConfiguration; +import org.apache.dubbo.config.spring.filter.MockFilter; +import org.apache.dubbo.config.spring.impl.DemoServiceImpl; +import org.apache.dubbo.config.spring.impl.HelloServiceImpl; +import org.apache.dubbo.config.spring.registry.MockRegistry; +import org.apache.dubbo.config.spring.registry.MockRegistryFactory; +import org.apache.dubbo.registry.Registry; +import org.apache.dubbo.registry.RegistryService; +import org.apache.dubbo.rpc.Exporter; +import org.apache.dubbo.rpc.Filter; +import org.apache.dubbo.rpc.RpcContext; +import org.apache.dubbo.rpc.RpcException; +import org.apache.dubbo.rpc.service.GenericException; +import org.apache.dubbo.rpc.service.GenericService; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import java.util.Collection; +import java.util.List; + +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; + + +/** + * ConfigTest + */ +@Ignore +public class ConfigTest { + + private static void unexportService(ServiceConfig config) { + if (config != null) { + config.unexport(); + } + } + + @Test + public void testSpringExtensionInject() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/spring-extension-inject.xml"); + ctx.start(); + try { + MockFilter filter = (MockFilter) ExtensionLoader.getExtensionLoader(Filter.class).getExtension("mymock"); + assertNotNull(filter.getMockDao()); + assertNotNull(filter.getProtocol()); + assertNotNull(filter.getLoadBalance()); + } finally { + ctx.stop(); + ctx.close(); + } + } + + @Test + public void testServiceClass() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/service-class.xml"); + ctx.start(); + try { + DemoService demoService = refer("dubbo://127.0.0.1:30887"); + String hello = demoService.sayName("hello"); + assertEquals("welcome:hello", hello); + } finally { + ctx.stop(); + ctx.close(); + } + } + + @Test + public void testServiceAnnotation() { + AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext(); + providerContext.register(ProviderConfiguration.class); + + providerContext.refresh(); + + ReferenceConfig reference = new ReferenceConfig(); + reference.setApplication(new ApplicationConfig("consumer")); + reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); + reference.setInterface(HelloService.class); + reference.setUrl("dubbo://127.0.0.1:12345"); + String hello = reference.get().sayHello("hello"); + assertEquals("Hello, hello", hello); + + } + + @Test + @SuppressWarnings("unchecked") + public void testProviderNestedService() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/provider-nested-service.xml"); + ctx.start(); + try { + ServiceConfig serviceConfig = (ServiceConfig) ctx.getBean("serviceConfig"); + assertNotNull(serviceConfig.getProvider()); + assertEquals(2000, serviceConfig.getProvider().getTimeout().intValue()); + + ServiceConfig serviceConfig2 = (ServiceConfig) ctx.getBean("serviceConfig2"); + assertNotNull(serviceConfig2.getProvider()); + assertEquals(1000, serviceConfig2.getProvider().getTimeout().intValue()); + } finally { + ctx.stop(); + ctx.close(); + } + } + + private DemoService refer(String url) { + ReferenceConfig reference = new ReferenceConfig(); + reference.setApplication(new ApplicationConfig("consumer")); + reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); + reference.setInterface(DemoService.class); + reference.setUrl(url); + return reference.get(); + } + + @Test + public void testToString() { + ReferenceConfig reference = new ReferenceConfig(); + reference.setApplication(new ApplicationConfig("consumer")); + reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); + reference.setInterface(DemoService.class); + reference.setUrl("dubbo://127.0.0.1:20881"); + String str = reference.toString(); + assertTrue(str.startsWith("")); + } + + @Test + public void testForks() { + ReferenceConfig reference = new ReferenceConfig(); + reference.setApplication(new ApplicationConfig("consumer")); + reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); + reference.setInterface(DemoService.class); + reference.setUrl("dubbo://127.0.0.1:20881"); + + int forks = 10; + reference.setForks(forks); + String str = reference.toString(); + assertTrue(str.contains("forks=\"" + forks + "\"")); + } + + @Test + public void testMultiProtocol() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-protocol.xml"); + ctx.start(); + try { + DemoService demoService = refer("dubbo://127.0.0.1:20881"); + String hello = demoService.sayName("hello"); + assertEquals("say:hello", hello); + } finally { + ctx.stop(); + ctx.close(); + } + } + + @Test + public void testMultiProtocolDefault() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-protocol-default.xml"); + ctx.start(); + try { + DemoService demoService = refer("rmi://127.0.0.1:10991"); + String hello = demoService.sayName("hello"); + assertEquals("say:hello", hello); + } finally { + ctx.stop(); + ctx.close(); + } + } + + @Test + public void testMultiProtocolError() { + try { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-protocol-error.xml"); + ctx.start(); + ctx.stop(); + ctx.close(); + } catch (BeanCreationException e) { + assertTrue(e.getMessage().contains("Found multi-protocols")); + } + } + + @Test + public void testMultiProtocolRegister() { + SimpleRegistryService registryService = new SimpleRegistryService(); + Exporter exporter = SimpleRegistryExporter.export(4547, registryService); + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-protocol-register.xml"); + ctx.start(); + try { + List urls = registryService.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); + assertNotNull(urls); + assertEquals(1, urls.size()); + assertEquals("dubbo://" + NetUtils.getLocalHost() + ":20824/org.apache.dubbo.config.spring.api.DemoService", urls.get(0).toIdentityString()); + } finally { + ctx.stop(); + ctx.close(); + exporter.unexport(); + } + } + + @Test + public void testMultiRegistry() { + SimpleRegistryService registryService1 = new SimpleRegistryService(); + Exporter exporter1 = SimpleRegistryExporter.export(4545, registryService1); + SimpleRegistryService registryService2 = new SimpleRegistryService(); + Exporter exporter2 = SimpleRegistryExporter.export(4546, registryService2); + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-registry.xml"); + ctx.start(); + try { + List urls1 = registryService1.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); + assertNull(urls1); + List urls2 = registryService2.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); + assertNotNull(urls2); + assertEquals(1, urls2.size()); + assertEquals("dubbo://" + NetUtils.getLocalHost() + ":20880/org.apache.dubbo.config.spring.api.DemoService", urls2.get(0).toIdentityString()); + } finally { + ctx.stop(); + ctx.close(); + exporter1.unexport(); + exporter2.unexport(); + } + } + + @Test + public void testDelayFixedTime() throws Exception { + SimpleRegistryService registryService = new SimpleRegistryService(); + Exporter exporter = SimpleRegistryExporter.export(4548, registryService); + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/delay-fixed-time.xml"); + ctx.start(); + try { + List urls = registryService.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); + assertNull(urls); + int i = 0; + while ((i++) < 60 && urls == null) { + urls = registryService.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); + Thread.sleep(10); + } + assertNotNull(urls); + assertEquals(1, urls.size()); + assertEquals("dubbo://" + NetUtils.getLocalHost() + ":20888/org.apache.dubbo.config.spring.api.DemoService", urls.get(0).toIdentityString()); + } finally { + ctx.stop(); + ctx.close(); + exporter.unexport(); + } + } + + @Test + public void testDelayOnInitialized() throws Exception { + SimpleRegistryService registryService = new SimpleRegistryService(); + Exporter exporter = SimpleRegistryExporter.export(4548, registryService); + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/delay-on-initialized.xml"); + //ctx.start(); + try { + List urls = registryService.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); + assertNotNull(urls); + assertEquals(1, urls.size()); + assertEquals("dubbo://" + NetUtils.getLocalHost() + ":20888/org.apache.dubbo.config.spring.api.DemoService", urls.get(0).toIdentityString()); + } finally { + ctx.stop(); + ctx.close(); + exporter.unexport(); + } + } + + @Test + public void testRmiTimeout() throws Exception { + if (System.getProperty("sun.rmi.transport.tcp.responseTimeout") != null) { + System.setProperty("sun.rmi.transport.tcp.responseTimeout", ""); + } + ConsumerConfig consumer = new ConsumerConfig(); + consumer.setTimeout(1000); + assertEquals("1000", System.getProperty("sun.rmi.transport.tcp.responseTimeout")); + consumer.setTimeout(2000); + assertEquals("1000", System.getProperty("sun.rmi.transport.tcp.responseTimeout")); + } + + @Test + public void testAutowireAndAOP() throws Exception { + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider.xml"); + providerContext.start(); + try { + ClassPathXmlApplicationContext byNameContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/aop-autowire-byname.xml"); + byNameContext.start(); + try { + DemoActionBySetter demoActionBySetter = (DemoActionBySetter) byNameContext.getBean("demoActionBySetter"); + assertNotNull(demoActionBySetter.getDemoService()); + assertEquals("aop:say:hello", demoActionBySetter.getDemoService().sayName("hello")); + DemoActionByAnnotation demoActionByAnnotation = (DemoActionByAnnotation) byNameContext.getBean("demoActionByAnnotation"); + assertNotNull(demoActionByAnnotation.getDemoService()); + assertEquals("aop:say:hello", demoActionByAnnotation.getDemoService().sayName("hello")); + } finally { + byNameContext.stop(); + byNameContext.close(); + } + ClassPathXmlApplicationContext byTypeContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/aop-autowire-bytype.xml"); + byTypeContext.start(); + try { + DemoActionBySetter demoActionBySetter = (DemoActionBySetter) byTypeContext.getBean("demoActionBySetter"); + assertNotNull(demoActionBySetter.getDemoService()); + assertEquals("aop:say:hello", demoActionBySetter.getDemoService().sayName("hello")); + DemoActionByAnnotation demoActionByAnnotation = (DemoActionByAnnotation) byTypeContext.getBean("demoActionByAnnotation"); + assertNotNull(demoActionByAnnotation.getDemoService()); + assertEquals("aop:say:hello", demoActionByAnnotation.getDemoService().sayName("hello")); + } finally { + byTypeContext.stop(); + byTypeContext.close(); + } + } finally { + providerContext.stop(); + providerContext.close(); + } + } + + @Test + public void testAppendFilter() throws Exception { + ProviderConfig provider = new ProviderConfig(); + provider.setFilter("classloader,monitor"); + ServiceConfig service = new ServiceConfig(); + service.setFilter("accesslog,trace"); + service.setProvider(provider); + service.setProtocol(new ProtocolConfig("dubbo", 20880)); + service.setApplication(new ApplicationConfig("provider")); + service.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + try { + service.export(); + List urls = service.toUrls(); + assertNotNull(urls); + assertEquals(1, urls.size()); + assertEquals("classloader,monitor,accesslog,trace", urls.get(0).getParameter("service.filter")); + + ConsumerConfig consumer = new ConsumerConfig(); + consumer.setFilter("classloader,monitor"); + ReferenceConfig reference = new ReferenceConfig(); + reference.setFilter("accesslog,trace"); + reference.setConsumer(consumer); + reference.setApplication(new ApplicationConfig("consumer")); + reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); + reference.setInterface(DemoService.class); + reference.setUrl("dubbo://" + NetUtils.getLocalHost() + ":20880?" + DemoService.class.getName() + "?check=false"); + try { + reference.get(); + urls = reference.toUrls(); + assertNotNull(urls); + assertEquals(1, urls.size()); + assertEquals("classloader,monitor,accesslog,trace", urls.get(0).getParameter("reference.filter")); + } finally { + reference.destroy(); + } + } finally { + service.unexport(); + } + } + + @Test + public void testInitReference() throws Exception { + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider.xml"); + providerContext.start(); + try { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/init-reference.xml"); + ctx.start(); + try { + DemoService demoService = (DemoService) ctx.getBean("demoService"); + assertEquals("say:world", demoService.sayName("world")); + } finally { + ctx.stop(); + ctx.close(); + } + } finally { + providerContext.stop(); + providerContext.close(); + } + } + + // DUBBO-571 methods key in provider's URLONE doesn't contain the methods from inherited super interface + @Test + public void test_noMethodInterface_methodsKeyHasValue() throws Exception { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider-no-methods-interface.xml"); + ctx.start(); + try { + ServiceBean bean = (ServiceBean) ctx.getBean("service"); + List urls = bean.getExportedUrls(); + assertEquals(1, urls.size()); + URL url = urls.get(0); + assertEquals("sayName,getBox", url.getParameter("methods")); + } finally { + ctx.stop(); + ctx.close(); + } + } + + // DUBBO-147 find all invoker instances which have been tried from RpcContext + @Test + public void test_RpcContext_getUrls() throws Exception { + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext( + ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider-long-waiting.xml"); + providerContext.start(); + + try { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + ConfigTest.class.getPackage().getName().replace('.', '/') + + "/init-reference-getUrls.xml"); + ctx.start(); + try { + DemoService demoService = (DemoService) ctx.getBean("demoService"); + try { + demoService.sayName("Haha"); + fail(); + } catch (RpcException expected) { + assertThat(expected.getMessage(), containsString("Tried 3 times")); + } + + assertEquals(3, RpcContext.getContext().getUrls().size()); + } finally { + ctx.stop(); + ctx.close(); + } + } finally { + providerContext.stop(); + providerContext.close(); + } + } + + // BUG: DUBBO-846 in version 2.0.9, config retry="false" on provider's method doesn't work + @Test + public void test_retrySettingFail() throws Exception { + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext( + ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider-long-waiting.xml"); + providerContext.start(); + + try { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + ConfigTest.class.getPackage().getName().replace('.', '/') + + "/init-reference-retry-false.xml"); + ctx.start(); + try { + DemoService demoService = (DemoService) ctx.getBean("demoService"); + try { + demoService.sayName("Haha"); + fail(); + } catch (RpcException expected) { + assertThat(expected.getMessage(), containsString("Tried 1 times")); + } + + assertEquals(1, RpcContext.getContext().getUrls().size()); + } finally { + ctx.stop(); + ctx.close(); + } + } finally { + providerContext.stop(); + providerContext.close(); + } + } + + // BuG: DUBBO-146 Provider doesn't have exception output, and consumer has timeout error when serialization fails + // for example, object transported on the wire doesn't implement Serializable + @Test + public void test_returnSerializationFail() throws Exception { + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider-UnserializableBox.xml"); + providerContext.start(); + try { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/init-reference.xml"); + ctx.start(); + try { + DemoService demoService = (DemoService) ctx.getBean("demoService"); + try { + demoService.getBox(); + fail(); + } catch (RpcException expected) { + assertThat(expected.getMessage(), containsString("must implement java.io.Serializable")); + } + } finally { + ctx.stop(); + ctx.close(); + } + } finally { + providerContext.stop(); + providerContext.close(); + } + } + + @Test + public void testXmlOverrideProperties() throws Exception { + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/xml-override-properties.xml"); + providerContext.start(); + try { + ApplicationConfig application = (ApplicationConfig) providerContext.getBean("application"); + assertEquals("demo-provider", application.getName()); + assertEquals("world", application.getOwner()); + + RegistryConfig registry = (RegistryConfig) providerContext.getBean("registry"); + assertEquals("N/A", registry.getAddress()); + + ProtocolConfig dubbo = (ProtocolConfig) providerContext.getBean("dubbo"); + assertEquals(20813, dubbo.getPort().intValue()); + + } finally { + providerContext.stop(); + providerContext.close(); + } + } + + @Test + public void testApiOverrideProperties() throws Exception { + ApplicationConfig application = new ApplicationConfig(); + application.setName("api-override-properties"); + + RegistryConfig registry = new RegistryConfig(); + registry.setAddress("N/A"); + + ProtocolConfig protocol = new ProtocolConfig(); + protocol.setName("dubbo"); + protocol.setPort(13123); + + ServiceConfig service = new ServiceConfig(); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + service.setApplication(application); + service.setRegistry(registry); + service.setProtocol(protocol); + service.export(); + + try { + URL url = service.toUrls().get(0); + assertEquals("api-override-properties", url.getParameter("application")); + assertEquals("world", url.getParameter("owner")); + assertEquals(13123, url.getPort()); + + ReferenceConfig reference = new ReferenceConfig(); + reference.setApplication(new ApplicationConfig("consumer")); + reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); + reference.setInterface(DemoService.class); + reference.setUrl("dubbo://127.0.0.1:13123"); + reference.get(); + try { + url = reference.toUrls().get(0); + assertEquals("2000", url.getParameter("timeout")); + } finally { + reference.destroy(); + } + } finally { + service.unexport(); + } + } + + @Test + public void testSystemPropertyOverrideProtocol() throws Exception { + System.setProperty("dubbo.protocol.port", "20812"); + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/override-protocol.xml"); + providerContext.start(); + try { + ProtocolConfig dubbo = (ProtocolConfig) providerContext.getBean("dubbo"); + assertEquals(20812, dubbo.getPort().intValue()); + } finally { + System.setProperty("dubbo.protocol.port", ""); + providerContext.stop(); + providerContext.close(); + } + } + + @Test + public void testSystemPropertyOverrideMultiProtocol() throws Exception { + System.setProperty("dubbo.protocol.dubbo.port", "20814"); + System.setProperty("dubbo.protocol.rmi.port", "10914"); + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/override-multi-protocol.xml"); + providerContext.start(); + try { + ProtocolConfig dubbo = (ProtocolConfig) providerContext.getBean("dubbo"); + assertEquals(20814, dubbo.getPort().intValue()); + ProtocolConfig rmi = (ProtocolConfig) providerContext.getBean("rmi"); + assertEquals(10914, rmi.getPort().intValue()); + } finally { + System.setProperty("dubbo.protocol.dubbo.port", ""); + System.setProperty("dubbo.protocol.rmi.port", ""); + providerContext.stop(); + providerContext.close(); + } + } + + @SuppressWarnings("unchecked") + @Test + public void testSystemPropertyOverrideXmlDefault() throws Exception { + System.setProperty("dubbo.application.name", "sysover"); + System.setProperty("dubbo.application.owner", "sysowner"); + System.setProperty("dubbo.registry.address", "N/A"); + System.setProperty("dubbo.protocol.name", "dubbo"); + System.setProperty("dubbo.protocol.port", "20819"); + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/system-properties-override-default.xml"); + providerContext.start(); + try { + ServiceConfig service = (ServiceConfig) providerContext.getBean("demoServiceConfig"); + assertEquals("sysover", service.getApplication().getName()); + assertEquals("sysowner", service.getApplication().getOwner()); + assertEquals("N/A", service.getRegistry().getAddress()); + assertEquals("dubbo", service.getProtocol().getName()); + assertEquals(20819, service.getProtocol().getPort().intValue()); + } finally { + System.setProperty("dubbo.application.name", ""); + System.setProperty("dubbo.application.owner", ""); + System.setProperty("dubbo.registry.address", ""); + System.setProperty("dubbo.protocol.name", ""); + System.setProperty("dubbo.protocol.port", ""); + providerContext.stop(); + providerContext.close(); + } + } + + @SuppressWarnings("unchecked") + @Test + public void testSystemPropertyOverrideXml() throws Exception { + System.setProperty("dubbo.application.name", "sysover"); + System.setProperty("dubbo.application.owner", "sysowner"); + System.setProperty("dubbo.registry.address", "N/A"); + System.setProperty("dubbo.protocol.name", "dubbo"); + System.setProperty("dubbo.protocol.port", "20819"); + System.setProperty("dubbo.service.register", "false"); + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/system-properties-override.xml"); + providerContext.start(); + try { + ServiceConfig service = (ServiceConfig) providerContext.getBean("demoServiceConfig"); + URL url = service.toUrls().get(0); + assertEquals("sysover", url.getParameter("application")); + assertEquals("sysowner", url.getParameter("owner")); + assertEquals("dubbo", url.getProtocol()); + assertEquals(20819, url.getPort()); + String register = url.getParameter("register"); + assertTrue(register != null && !"".equals(register)); + assertEquals(false, Boolean.valueOf(register)); + } finally { + System.setProperty("dubbo.application.name", ""); + System.setProperty("dubbo.application.owner", ""); + System.setProperty("dubbo.registry.address", ""); + System.setProperty("dubbo.protocol.name", ""); + System.setProperty("dubbo.protocol.port", ""); + System.setProperty("dubbo.service.register", ""); + providerContext.stop(); + providerContext.close(); + } + } + + @Test + public void testSystemPropertyOverrideReferenceConfig() throws Exception { + System.setProperty("dubbo.reference.retries", "5"); + + try { + ServiceConfig service = new ServiceConfig(); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + service.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); + ProtocolConfig protocolConfig = new ProtocolConfig("injvm"); + service.setProtocol(protocolConfig); + service.export(); + + ReferenceConfig reference = new ReferenceConfig(); + reference.setInterface(DemoService.class); + reference.setInjvm(true); + reference.setRetries(2); + reference.get(); + assertEquals(Integer.valueOf(5), reference.getRetries()); + } finally { + System.setProperty("dubbo.reference.retries", ""); + } + } + + @Test + public void testSystemPropertyOverrideApiDefault() throws Exception { + System.setProperty("dubbo.application.name", "sysover"); + System.setProperty("dubbo.application.owner", "sysowner"); + System.setProperty("dubbo.registry.address", "N/A"); + System.setProperty("dubbo.protocol.name", "dubbo"); + System.setProperty("dubbo.protocol.port", "20834"); + try { + ServiceConfig serviceConfig = new ServiceConfig(); + serviceConfig.setInterface(DemoService.class); + serviceConfig.setRef(new DemoServiceImpl()); + serviceConfig.export(); + try { + assertEquals("sysover", serviceConfig.getApplication().getName()); + assertEquals("sysowner", serviceConfig.getApplication().getOwner()); + assertEquals("N/A", serviceConfig.getRegistry().getAddress()); + assertEquals("dubbo", serviceConfig.getProtocol().getName()); + assertEquals(20834, serviceConfig.getProtocol().getPort().intValue()); + } finally { + serviceConfig.unexport(); + } + } finally { + System.setProperty("dubbo.application.name", ""); + System.setProperty("dubbo.application.owner", ""); + System.setProperty("dubbo.registry.address", ""); + System.setProperty("dubbo.protocol.name", ""); + System.setProperty("dubbo.protocol.port", ""); + } + } + + @Test + public void testSystemPropertyOverrideApi() throws Exception { + System.setProperty("dubbo.application.name", "sysover"); + System.setProperty("dubbo.application.owner", "sysowner"); + System.setProperty("dubbo.registry.address", "N/A"); + System.setProperty("dubbo.protocol.name", "dubbo"); + System.setProperty("dubbo.protocol.port", "20834"); + try { + ApplicationConfig application = new ApplicationConfig(); + application.setName("aaa"); + + RegistryConfig registry = new RegistryConfig(); + registry.setAddress("127.0.0.1"); + + ProtocolConfig protocol = new ProtocolConfig(); + protocol.setName("rmi"); + protocol.setPort(1099); + + ServiceConfig service = new ServiceConfig(); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + service.setApplication(application); + service.setRegistry(registry); + service.setProtocol(protocol); + service.export(); + + try { + URL url = service.toUrls().get(0); + assertEquals("sysover", url.getParameter("application")); + assertEquals("sysowner", url.getParameter("owner")); + assertEquals("dubbo", url.getProtocol()); + assertEquals(20834, url.getPort()); + } finally { + service.unexport(); + } + } finally { + System.setProperty("dubbo.application.name", ""); + System.setProperty("dubbo.application.owner", ""); + System.setProperty("dubbo.registry.address", ""); + System.setProperty("dubbo.protocol.name", ""); + System.setProperty("dubbo.protocol.port", ""); + } + } + + @Test + public void testSystemPropertyOverrideProperties() throws Exception { + String portString = System.getProperty("dubbo.protocol.port"); + System.clearProperty("dubbo.protocol.port"); + try { + int port = 1234; + System.setProperty("dubbo.protocol.port", String.valueOf(port)); + ApplicationConfig application = new ApplicationConfig(); + application.setName("aaa"); + + RegistryConfig registry = new RegistryConfig(); + registry.setAddress("N/A"); + + ProtocolConfig protocol = new ProtocolConfig(); + protocol.setName("rmi"); + + ServiceConfig service = new ServiceConfig(); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + service.setApplication(application); + service.setRegistry(registry); + service.setProtocol(protocol); + service.export(); + + try { + URL url = service.toUrls().get(0); + // from api + assertEquals("aaa", url.getParameter("application")); + // from dubbo.properties + assertEquals("world", url.getParameter("owner")); + // from system property + assertEquals(1234, url.getPort()); + } finally { + service.unexport(); + } + } finally { + if (portString != null) { + System.setProperty("dubbo.protocol.port", portString); + } + } + } + + @Test + @SuppressWarnings("unchecked") + public void testCustomizeParameter() throws Exception { + ClassPathXmlApplicationContext context = + new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/customize-parameter.xml"); + context.start(); + ServiceBean serviceBean = (ServiceBean) context.getBean("demoServiceExport"); + URL url = (URL) serviceBean.toUrls().get(0); + assertEquals("protocol-paramA", url.getParameter("protocol.paramA")); + assertEquals("service-paramA", url.getParameter("service.paramA")); + } + + @Test + public void testPath() throws Exception { + ServiceConfig service = new ServiceConfig(); + service.setPath("a/b$c"); + try { + service.setPath("a?b"); + fail(); + } catch (IllegalStateException e) { + assertTrue(e.getMessage().contains("")); + } + } + + @Test + public void testAnnotation() { + SimpleRegistryService registryService = new SimpleRegistryService(); + Exporter exporter = SimpleRegistryExporter.export(4548, registryService); + try { + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/annotation-provider.xml"); + providerContext.start(); + try { + ClassPathXmlApplicationContext consumerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/annotation-consumer.xml"); + consumerContext.start(); + try { + AnnotationAction annotationAction = (AnnotationAction) consumerContext.getBean("annotationAction"); + String hello = annotationAction.doSayName("hello"); + assertEquals("annotation:hello", hello); + } finally { + consumerContext.stop(); + consumerContext.close(); + } + } finally { + providerContext.stop(); + providerContext.close(); + } + } finally { + exporter.unexport(); + } + } + + @Test + public void testDubboProtocolPortOverride() throws Exception { + String dubboPort = System.getProperty("dubbo.protocol.dubbo.port"); + int port = 55555; + System.setProperty("dubbo.protocol.dubbo.port", String.valueOf(port)); + ServiceConfig service = null; + try { + ApplicationConfig application = new ApplicationConfig(); + application.setName("dubbo-protocol-port-override"); + + RegistryConfig registry = new RegistryConfig(); + registry.setAddress("N/A"); + + ProtocolConfig protocol = new ProtocolConfig(); + + service = new ServiceConfig(); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + service.setApplication(application); + service.setRegistry(registry); + service.setProtocol(protocol); + service.export(); + + Assert.assertEquals(port, service.getExportedUrls().get(0).getPort()); + } finally { + if (StringUtils.isNotEmpty(dubboPort)) { + System.setProperty("dubbo.protocol.dubbo.port", dubboPort); + } + if (service != null) { + service.unexport(); + } + } + } + + @Test + public void testProtocolRandomPort() throws Exception { + ServiceConfig demoService = null; + ServiceConfig helloService = null; + + ApplicationConfig application = new ApplicationConfig(); + application.setName("test-protocol-random-port"); + + RegistryConfig registry = new RegistryConfig(); + registry.setAddress("N/A"); + + ProtocolConfig protocol = new ProtocolConfig(); + protocol.setName("dubbo"); + protocol.setPort(-1); + + demoService = new ServiceConfig(); + demoService.setInterface(DemoService.class); + demoService.setRef(new DemoServiceImpl()); + demoService.setApplication(application); + demoService.setRegistry(registry); + demoService.setProtocol(protocol); + + helloService = new ServiceConfig(); + helloService.setInterface(HelloService.class); + helloService.setRef(new HelloServiceImpl()); + helloService.setApplication(application); + helloService.setRegistry(registry); + helloService.setProtocol(protocol); + + try { + demoService.export(); + helloService.export(); + + Assert.assertEquals(demoService.getExportedUrls().get(0).getPort(), + helloService.getExportedUrls().get(0).getPort()); + } finally { + unexportService(demoService); + unexportService(helloService); + } + } + + @Test + public void testReferGenericExport() throws Exception { + ApplicationConfig ac = new ApplicationConfig("test-refer-generic-export"); + RegistryConfig rc = new RegistryConfig(); + rc.setAddress(RegistryConfig.NO_AVAILABLE); + + ServiceConfig sc = new ServiceConfig(); + sc.setApplication(ac); + sc.setRegistry(rc); + sc.setInterface(DemoService.class.getName()); + sc.setRef(new GenericService() { + + public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException { + return null; + } + }); + + ReferenceConfig ref = new ReferenceConfig(); + ref.setApplication(ac); + ref.setRegistry(rc); + ref.setInterface(DemoService.class.getName()); + + try { + sc.export(); + ref.get(); + Assert.fail(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + sc.unexport(); + ref.destroy(); + } + } + + @Test + public void testGenericServiceConfig() throws Exception { + ServiceConfig service = new ServiceConfig(); + service.setApplication(new ApplicationConfig("test")); + service.setRegistry(new RegistryConfig("mock://localhost")); + service.setInterface(DemoService.class.getName()); + service.setGeneric(Constants.GENERIC_SERIALIZATION_BEAN); + service.setRef(new GenericService() { + + public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException { + return null; + } + }); + try { + service.export(); + Collection collection = MockRegistryFactory.getCachedRegistry(); + MockRegistry registry = (MockRegistry) collection.iterator().next(); + URL url = registry.getRegistered().get(0); + Assert.assertEquals(Constants.GENERIC_SERIALIZATION_BEAN, url.getParameter(Constants.GENERIC_KEY)); + } finally { + MockRegistryFactory.cleanCachedRegistry(); + service.unexport(); + } + } + + @Test + public void testGenericServiceConfigThroughSpring() throws Exception { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/generic-export.xml"); + try { + ctx.start(); + ServiceConfig serviceConfig = (ServiceConfig) ctx.getBean("dubboDemoService"); + URL url = (URL) serviceConfig.getExportedUrls().get(0); + Assert.assertEquals(Constants.GENERIC_SERIALIZATION_BEAN, url.getParameter(Constants.GENERIC_KEY)); + } finally { + ctx.destroy(); + } + } } \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ServiceBeanTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ServiceBeanTest.java index 467baf50be4..b4164569e12 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ServiceBeanTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ServiceBeanTest.java @@ -17,6 +17,7 @@ package org.apache.dubbo.config.spring; import org.apache.dubbo.config.annotation.Service; + import org.junit.Assert; import org.junit.Test; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/action/DemoActionByAnnotation.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/action/DemoActionByAnnotation.java index f39ff2e6814..6f0ea410555 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/action/DemoActionByAnnotation.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/action/DemoActionByAnnotation.java @@ -1,34 +1,35 @@ -/* - * 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.action; - -import org.apache.dubbo.config.spring.api.DemoService; -import org.springframework.beans.factory.annotation.Autowired; - -/** - * DemoAction - */ -public class DemoActionByAnnotation { - - @Autowired - private DemoService demoService; - - public DemoService getDemoService() { - return demoService; - } - +/* + * 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.action; + +import org.apache.dubbo.config.spring.api.DemoService; + +import org.springframework.beans.factory.annotation.Autowired; + +/** + * DemoAction + */ +public class DemoActionByAnnotation { + + @Autowired + private DemoService demoService; + + public DemoService getDemoService() { + return demoService; + } + } \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/annotation/consumer/AnnotationAction.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/annotation/consumer/AnnotationAction.java index be6844532b4..35d94fecf04 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/annotation/consumer/AnnotationAction.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/annotation/consumer/AnnotationAction.java @@ -1,36 +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 org.apache.dubbo.config.spring.annotation.consumer; - -import org.apache.dubbo.config.annotation.Reference; -import org.apache.dubbo.config.spring.api.DemoService; -import org.springframework.stereotype.Controller; - -/** - * AnnotationAction - */ -@Controller("annotationAction") -public class AnnotationAction { - - @Reference(version = "1.2") - private DemoService demoService; - - public String doSayName(String name) { - return demoService.sayName(name); - } - +/* + * 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.annotation.consumer; + +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.spring.api.DemoService; + +import org.springframework.stereotype.Controller; + +/** + * AnnotationAction + */ +@Controller("annotationAction") +public class AnnotationAction { + + @Reference(version = "1.2") + private DemoService demoService; + + public String doSayName(String name) { + return demoService.sayName(name); + } + } \ 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/AnnotationPropertyValuesAdapterTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapterTest.java index 94148e66d74..0baa7bbe450 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 @@ -21,6 +21,7 @@ import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.spring.ReferenceBean; import org.apache.dubbo.config.spring.api.DemoService; + import org.junit.Assert; import org.junit.Test; import org.springframework.core.annotation.AnnotationUtils; @@ -124,7 +125,6 @@ public Map convert(String[] source) { Assert.assertEquals("cache", referenceBean.getCache()); Assert.assertEquals("default,default", referenceBean.getFilter()); Assert.assertEquals("default,default", referenceBean.getListener()); - Assert.assertEquals("protocol", referenceBean.getProtocol()); Map data = new LinkedHashMap(); data.put("key1", "value1"); @@ -142,7 +142,7 @@ public Map convert(String[] source) { private static class TestBean { @Reference( - interfaceClass = DemoService.class, interfaceName = "org.apache.dubbo.config.spring.api.DemoService", version = "${version}", group = "group", + 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", @@ -151,7 +151,7 @@ private static class TestBean { 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"}, protocol = "protocol" + module = "module", consumer = "consumer", monitor = "monitor", registry = {"registry1", "registry2"} ) private DemoService demoService; 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 ec6e49a99e1..52927e61082 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 @@ -19,6 +19,7 @@ import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.spring.context.properties.DefaultDubboConfigBinder; import org.apache.dubbo.config.spring.context.properties.DubboConfigBinder; + 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/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java index 253ecf8a45a..6f626784db3 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java @@ -17,83 +17,73 @@ package org.apache.dubbo.config.spring.beans.factory.annotation; import org.apache.dubbo.config.annotation.Reference; -import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.config.spring.ReferenceBean; import org.apache.dubbo.config.spring.api.DemoService; -import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan; -import org.junit.After; import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; +import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.InjectionMetadata; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.ImportResource; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; import java.util.Collection; import java.util.Map; import static org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor.BEAN_NAME; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.hamcrest.MatcherAssert.assertThat; /** * {@link ReferenceAnnotationBeanPostProcessor} Test * * @since 2.5.7 */ +@RunWith(SpringRunner.class) +@ContextConfiguration( + classes = { + ServiceAnnotationTestConfiguration.class, + ReferenceAnnotationBeanPostProcessorTest.class + }) +@TestPropertySource(properties = { + "packagesToScan = org.apache.dubbo.config.spring.context.annotation.provider", + "consumer.version = ${demo.service.version}", + "consumer.url = dubbo://127.0.0.1:12345", +}) public class ReferenceAnnotationBeanPostProcessorTest { - private ConfigurableApplicationContext providerApplicationContext; - - @BeforeClass - public static void prepare() { - System.setProperty("provider.version", "1.2"); - System.setProperty("package1", "org.apache.dubbo.config.spring.annotation.provider"); - System.setProperty("packagesToScan", "${package1}"); - System.setProperty("consumer.version", "1.2"); - System.setProperty("consumer.url", "dubbo://127.0.0.1:12345"); + @Bean + public TestBean testBean() { + return new TestBean(); } - @Before - public void init() { - // Starts Provider - providerApplicationContext = new AnnotationConfigApplicationContext(ServiceAnnotationBeanPostProcessorTest.TestConfiguration.class); - ConfigManager.getInstance().clear(); + @Bean(BEAN_NAME) + public ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor() { + return new ReferenceAnnotationBeanPostProcessor(); } - @After - public void destroy() { - // Shutdowns Provider - providerApplicationContext.close(); - ConfigManager.getInstance().clear(); - } + @Autowired + private ConfigurableApplicationContext context; @Test public void test() throws Exception { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); - TestBean testBean = context.getBean(TestBean.class); + DemoService demoService = testBean.getDemoService(); + + Assert.assertEquals("Hello,Mercy", demoService.sayName("Mercy")); + Assert.assertNotNull(testBean.getDemoServiceFromAncestor()); Assert.assertNotNull(testBean.getDemoServiceFromParent()); Assert.assertNotNull(testBean.getDemoService()); - Assert.assertEquals(testBean.getDemoServiceFromAncestor(), testBean.getDemoServiceFromParent()); - Assert.assertEquals(testBean.getDemoService(), testBean.getDemoServiceFromParent()); - - DemoService demoService = testBean.getDemoService(); - - Assert.assertEquals("annotation:Mercy", demoService.sayName("Mercy")); - - context.close(); + Assert.assertEquals("Hello,Mercy", testBean.getDemoServiceFromAncestor().sayName("Mercy")); + Assert.assertEquals("Hello,Mercy", testBean.getDemoServiceFromParent().sayName("Mercy")); + Assert.assertEquals("Hello,Mercy", testBean.getDemoService().sayName("Mercy")); } @@ -103,35 +93,24 @@ public void test() throws Exception { @Test public void testGetReferenceBeans() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); - ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class); Collection> referenceBeans = beanPostProcessor.getReferenceBeans(); - /** - * 1 -> demoService、demoServiceShouldBeSame - * 1 -> demoServiceShouldNotBeSame - * 1 -> demoServiceWithArray、demoServiceWithArrayShouldBeSame - */ - Assert.assertEquals(3, referenceBeans.size()); + Assert.assertEquals(1, referenceBeans.size()); ReferenceBean referenceBean = referenceBeans.iterator().next(); TestBean testBean = context.getBean(TestBean.class); - Assert.assertEquals(referenceBean.get(), testBean.getDemoServiceFromAncestor()); - Assert.assertEquals(referenceBean.get(), testBean.getDemoServiceFromParent()); - Assert.assertEquals(referenceBean.get(), testBean.getDemoService()); + Assert.assertNotNull(referenceBean.get()); } @Test public void testGetInjectedFieldReferenceBeanMap() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); - ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class); @@ -139,21 +118,18 @@ public void testGetInjectedFieldReferenceBeanMap() { Map> referenceBeanMap = beanPostProcessor.getInjectedFieldReferenceBeanMap(); - /** - * contains 5 fields. - */ - Assert.assertEquals(5, referenceBeanMap.size()); + Assert.assertEquals(1, referenceBeanMap.size()); for (Map.Entry> entry : referenceBeanMap.entrySet()) { InjectionMetadata.InjectedElement injectedElement = entry.getKey(); - Assert.assertEquals("org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor$ReferenceFieldElement", + Assert.assertEquals("org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedFieldElement", injectedElement.getClass().getName()); ReferenceBean referenceBean = entry.getValue(); - Assert.assertEquals("1.2", referenceBean.getVersion()); + Assert.assertEquals("2.5.7", referenceBean.getVersion()); Assert.assertEquals("dubbo://127.0.0.1:12345", referenceBean.getUrl()); } @@ -163,8 +139,6 @@ public void testGetInjectedFieldReferenceBeanMap() { @Test public void testGetInjectedMethodReferenceBeanMap() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); - ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class); @@ -178,79 +152,35 @@ public void testGetInjectedMethodReferenceBeanMap() { InjectionMetadata.InjectedElement injectedElement = entry.getKey(); - Assert.assertEquals("org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor$ReferenceMethodElement", + Assert.assertEquals("org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedMethodElement", injectedElement.getClass().getName()); ReferenceBean referenceBean = entry.getValue(); - Assert.assertEquals("1.2", referenceBean.getVersion()); + Assert.assertEquals("2.5.7", referenceBean.getVersion()); Assert.assertEquals("dubbo://127.0.0.1:12345", referenceBean.getUrl()); } } - @Test - public void testModuleInfo() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); - - ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME, - ReferenceAnnotationBeanPostProcessor.class); - - - Map> referenceBeanMap = - beanPostProcessor.getInjectedMethodReferenceBeanMap(); - - for (Map.Entry> entry : referenceBeanMap.entrySet()) { - ReferenceBean referenceBean = entry.getValue(); - - assertThat(referenceBean.getModule().getName(),is("defaultModule")); - assertThat(referenceBean.getMonitor(), not(nullValue())); - } - } - - @Test - public void testReferenceCache() throws Exception { - - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); - - TestBean testBean = context.getBean(TestBean.class); - - Assert.assertNotNull(testBean.getDemoServiceFromAncestor()); - Assert.assertNotNull(testBean.getDemoServiceFromParent()); - Assert.assertNotNull(testBean.getDemoService()); - - Assert.assertEquals(testBean.getDemoServiceFromAncestor(), testBean.getDemoServiceFromParent()); - Assert.assertEquals(testBean.getDemoService(), testBean.getDemoServiceFromParent()); - - DemoService demoService = testBean.getDemoService(); - - Assert.assertEquals(demoService, testBean.getDemoServiceShouldBeSame()); - Assert.assertNotEquals(demoService, testBean.getDemoServiceShouldNotBeSame()); - - context.close(); - - } - - @Test - public void testReferenceCacheWithArray() throws Exception { - - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); - - TestBean testBean = context.getBean(TestBean.class); - - Assert.assertNotNull(testBean.getDemoServiceFromAncestor()); - Assert.assertNotNull(testBean.getDemoServiceFromParent()); - Assert.assertNotNull(testBean.getDemoService()); - - Assert.assertEquals(testBean.getDemoServiceFromAncestor(), testBean.getDemoServiceFromParent()); - Assert.assertEquals(testBean.getDemoService(), testBean.getDemoServiceFromParent()); - - Assert.assertEquals(testBean.getDemoServiceWithArray(), testBean.getDemoServiceWithArrayShouldBeSame()); - - context.close(); - - } +// @Test +// public void testModuleInfo() { +// +// ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME, +// ReferenceAnnotationBeanPostProcessor.class); +// +// +// Map> referenceBeanMap = +// beanPostProcessor.getInjectedMethodReferenceBeanMap(); +// +// for (Map.Entry> entry : referenceBeanMap.entrySet()) { +// ReferenceBean referenceBean = entry.getValue(); +// +// assertThat(referenceBean.getModule().getName(), is("defaultModule")); +// assertThat(referenceBean.getMonitor(), not(nullValue())); +// } +// } private static class AncestorBean { @@ -264,7 +194,7 @@ public DemoService getDemoServiceFromAncestor() { return demoServiceFromAncestor; } - @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345") + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345") public void setDemoServiceFromAncestor(DemoService demoServiceFromAncestor) { this.demoServiceFromAncestor = demoServiceFromAncestor; } @@ -288,25 +218,10 @@ public DemoService getDemoServiceFromParent() { } - @ImportResource("META-INF/spring/dubbo-annotation-consumer.xml") - @DubboComponentScan(basePackageClasses = ReferenceAnnotationBeanPostProcessorTest.class) static class TestBean extends ParentBean { private DemoService demoService; - @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345") - private DemoService demoServiceShouldBeSame; - - @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345", async = true) - private DemoService demoServiceShouldNotBeSame; - - - @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345", parameters = { "key1", "value1"}) - private DemoService demoServiceWithArray; - - @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345", parameters = { "key1", "value1"}) - private DemoService demoServiceWithArrayShouldBeSame; - @Autowired private ApplicationContext applicationContext; @@ -314,26 +229,10 @@ public DemoService getDemoService() { return demoService; } - @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345") + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345") public void setDemoService(DemoService demoService) { this.demoService = demoService; } - - public DemoService getDemoServiceShouldNotBeSame() { - return demoServiceShouldNotBeSame; - } - - public DemoService getDemoServiceShouldBeSame() { - return demoServiceShouldBeSame; - } - - public DemoService getDemoServiceWithArray() { - return demoServiceWithArray; - } - - public DemoService getDemoServiceWithArrayShouldBeSame() { - return demoServiceWithArrayShouldBeSame; - } } } \ 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/ReferenceBeanBuilderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java new file mode 100644 index 00000000000..27f6c9663ed --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.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.config.spring.beans.factory.annotation; + + +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.spring.ReferenceBean; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; +import static org.springframework.util.ReflectionUtils.findField; + +/** + * {@link ReferenceBeanBuilder} Test + * + * @author Mercy + * @see ReferenceBeanBuilder + * @see Reference + * @since 2.6.4 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = ReferenceBeanBuilderTest.class) +public class ReferenceBeanBuilderTest { + + @Reference( + interfaceClass = CharSequence.class, + interfaceName = "java.lang.CharSequence", + version = "1.0.0", group = "TEST_GROUP", url = "dubbo://localhost:12345", + client = "client", generic = true, injvm = true, + check = false, init = false, lazy = true, + stubevent = true, reconnect = "reconnect", sticky = true, + proxy = "javassist", stub = "java.lang.CharSequence", cluster = "failover", + connections = 3, callbacks = 1, onconnect = "onconnect", ondisconnect = "ondisconnect", + owner = "owner", layer = "layer", retries = 1, + loadbalance = "random", async = true, actives = 3, + sent = true, mock = "mock", validation = "validation", + timeout = 3, cache = "cache", filter = {"echo", "generic", "accesslog"}, + listener = {"deprecated"}, parameters = {"n1=v1 ", "n2 = v2 ", " n3 = v3 "}, + application = "application", + module = "module", consumer = "consumer", monitor = "monitor", registry = {"registry"} + ) + private static final Object TEST_FIELD = new Object(); + + @Autowired + private ApplicationContext context; + + @Test + public void testBuild() throws Exception { + Reference reference = findAnnotation(findField(getClass(), "TEST_FIELD"), Reference.class); + ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder.create(reference, context.getClassLoader(), context); + beanBuilder.interfaceClass(CharSequence.class); + ReferenceBean referenceBean = beanBuilder.build(); + Assert.assertEquals(CharSequence.class, referenceBean.getInterfaceClass()); + Assert.assertEquals("1.0.0", referenceBean.getVersion()); + Assert.assertEquals("TEST_GROUP", referenceBean.getGroup()); + Assert.assertEquals("dubbo://localhost:12345", referenceBean.getUrl()); + Assert.assertEquals("client", referenceBean.getClient()); + Assert.assertEquals(true, referenceBean.isGeneric()); + Assert.assertEquals(true, referenceBean.isInjvm()); + Assert.assertEquals(false, referenceBean.isCheck()); + Assert.assertEquals(null, referenceBean.isInit()); + Assert.assertEquals(true, referenceBean.getLazy()); + Assert.assertEquals(true, referenceBean.getStubevent()); + Assert.assertEquals("reconnect", referenceBean.getReconnect()); + Assert.assertEquals(true, referenceBean.getSticky()); + Assert.assertEquals("javassist", referenceBean.getProxy()); + Assert.assertEquals("java.lang.CharSequence", referenceBean.getStub()); + Assert.assertEquals("failover", referenceBean.getCluster()); + Assert.assertEquals(Integer.valueOf(3), referenceBean.getConnections()); + Assert.assertEquals(Integer.valueOf(1), referenceBean.getCallbacks()); + Assert.assertEquals("onconnect", referenceBean.getOnconnect()); + Assert.assertEquals("ondisconnect", referenceBean.getOndisconnect()); + Assert.assertEquals("owner", referenceBean.getOwner()); + Assert.assertEquals("layer", referenceBean.getLayer()); + Assert.assertEquals(Integer.valueOf(1), referenceBean.getRetries()); + Assert.assertEquals("random", referenceBean.getLoadbalance()); + Assert.assertEquals(true, referenceBean.isAsync()); + Assert.assertEquals(Integer.valueOf(3), referenceBean.getActives()); + Assert.assertEquals(true, referenceBean.getSent()); + Assert.assertEquals("mock", referenceBean.getMock()); + Assert.assertEquals("validation", referenceBean.getValidation()); + Assert.assertEquals(Integer.valueOf(3), referenceBean.getTimeout()); + Assert.assertEquals("cache", referenceBean.getCache()); + Assert.assertEquals("echo,generic,accesslog", referenceBean.getFilter()); + Assert.assertEquals("deprecated", referenceBean.getListener()); + + // parameters + Map parameters = new HashMap(); + parameters.put("n1", "v1"); + parameters.put("n2", "v2"); + parameters.put("n3", "v3"); + Assert.assertEquals(parameters, referenceBean.getParameters()); + + // Asserts Null fields + Assert.assertNull(referenceBean.getApplication()); + Assert.assertNull(referenceBean.getModule()); + Assert.assertNull(referenceBean.getConsumer()); + Assert.assertNull(referenceBean.getMonitor()); + Assert.assertEquals(Collections.emptyList(), referenceBean.getRegistries()); + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessorTest.java index 35de555c30d..22325d96ebf 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessorTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessorTest.java @@ -18,6 +18,7 @@ import org.apache.dubbo.config.spring.ServiceBean; import org.apache.dubbo.config.spring.api.HelloService; + import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -25,9 +26,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.ImportResource; -import org.springframework.context.annotation.PropertySource; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; @@ -41,17 +39,25 @@ */ @RunWith(SpringRunner.class) @ContextConfiguration( - classes = {ServiceAnnotationBeanPostProcessorTest.TestConfiguration.class}) + classes = { + ServiceAnnotationTestConfiguration.class, + ServiceAnnotationBeanPostProcessorTest.class + }) @TestPropertySource(properties = { - "package1 = org.apache.dubbo.config.spring.context.annotation", - "packagesToScan = ${package1}", - "provider.version = 1.2" + "provider.package = org.apache.dubbo.config.spring.context.annotation.provider", + "packagesToScan = ${provider.package}", }) public class ServiceAnnotationBeanPostProcessorTest { @Autowired private ConfigurableListableBeanFactory beanFactory; + @Bean + public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor2 + (@Value("${packagesToScan}") String... packagesToScan) { + return new ServiceAnnotationBeanPostProcessor(packagesToScan); + } + @Test public void test() { @@ -61,38 +67,16 @@ public void test() { Map serviceBeansMap = beanFactory.getBeansOfType(ServiceBean.class); - Assert.assertEquals(3, serviceBeansMap.size()); + Assert.assertEquals(2, serviceBeansMap.size()); Map beanPostProcessorsMap = beanFactory.getBeansOfType(ServiceAnnotationBeanPostProcessor.class); - Assert.assertEquals(4, beanPostProcessorsMap.size()); + Assert.assertEquals(2, beanPostProcessorsMap.size()); - Assert.assertTrue(beanPostProcessorsMap.containsKey("doubleServiceAnnotationBeanPostProcessor")); - Assert.assertTrue(beanPostProcessorsMap.containsKey("emptyServiceAnnotationBeanPostProcessor")); Assert.assertTrue(beanPostProcessorsMap.containsKey("serviceAnnotationBeanPostProcessor")); Assert.assertTrue(beanPostProcessorsMap.containsKey("serviceAnnotationBeanPostProcessor2")); } - @ImportResource("META-INF/spring/dubbo-annotation-provider.xml") - @PropertySource("META-INF/default.properties") - @ComponentScan("org.apache.dubbo.config.spring.context.annotation.provider") - public static class TestConfiguration { - - @Bean - public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor - (@Value("${packagesToScan}") String... packagesToScan) { - return new ServiceAnnotationBeanPostProcessor(packagesToScan); - } - - @Bean - public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor2 - (@Value("${packagesToScan}") String... packagesToScan) { - return new ServiceAnnotationBeanPostProcessor(packagesToScan); - } - - - } - } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationTestConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationTestConfiguration.java new file mode 100644 index 00000000000..7a206db7852 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationTestConfiguration.java @@ -0,0 +1,116 @@ +/* + * 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.ApplicationConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.annotation.Service; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.PropertySource; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionException; +import org.springframework.transaction.TransactionStatus; + +/** + * {@link Service} Bean + * + * @since 2.6.5 + */ +@PropertySource("classpath:/META-INF/default.properties") +public class ServiceAnnotationTestConfiguration { + + /** + * Current application configuration, to replace XML config: + * + * <dubbo:application name="dubbo-demo-application"/> + * + * + * @return {@link ApplicationConfig} Bean + */ + @Bean("dubbo-demo-application") + public ApplicationConfig applicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("dubbo-demo-application"); + return applicationConfig; + } + + /** + * Current registry center configuration, to replace XML config: + * + * <dubbo:registry id="my-registry" address="N/A"/> + * + * + * @return {@link RegistryConfig} Bean + */ + @Bean("my-registry") + public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress("N/A"); + return registryConfig; + } + + /** + * Current protocol configuration, to replace XML config: + * + * <dubbo:protocol name="dubbo" port="12345"/> + * + * + * @return {@link ProtocolConfig} Bean + */ + @Bean("dubbo") + public ProtocolConfig protocolConfig() { + ProtocolConfig protocolConfig = new ProtocolConfig(); + protocolConfig.setName("dubbo"); + protocolConfig.setPort(12345); + return protocolConfig; + } + + @Primary + @Bean + public PlatformTransactionManager platformTransactionManager() { + return new PlatformTransactionManager() { + + @Override + public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException { + return null; + } + + @Override + public void commit(TransactionStatus status) throws TransactionException { + + } + + @Override + public void rollback(TransactionStatus status) throws TransactionException { + + } + }; + } + + @Bean + public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor + (@Value("${packagesToScan}") String... packagesToScan) { + return new ServiceAnnotationBeanPostProcessor(packagesToScan); + } + +} \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/java/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/ServiceBeanNameBuilderTest.java new file mode 100644 index 00000000000..5d4216043cc --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package 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.api.DemoService; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.mock.env.MockEnvironment; +import org.springframework.util.ReflectionUtils; + + +/** + * {@link ServiceBeanNameBuilder} Test + * + * @see ServiceBeanNameBuilder + * @since 2.6.5 + */ +@Service(interfaceClass = DemoService.class, group = ServiceBeanNameBuilderTest.GROUP, version = ServiceBeanNameBuilderTest.VERSION, + application = "application", module = "module", registry = {"1", "2", "3"}) +public class ServiceBeanNameBuilderTest { + + @Reference(interfaceClass = DemoService.class, group = "DUBBO", version = "1.0.0", + application = "application", module = "module", registry = {"1", "2", "3"}) + static final Class INTERFACE_CLASS = DemoService.class; + + static final String GROUP = "DUBBO"; + + static final String VERSION = "1.0.0"; + + static final String BEAN_NAME = "ServiceBean:org.apache.dubbo.config.spring.api.DemoService:1.0.0:DUBBO"; + + private MockEnvironment environment = new MockEnvironment(); + + @Test + public void testRequiredAttributes() { + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(INTERFACE_CLASS, environment); + Assert.assertEquals("ServiceBean:org.apache.dubbo.config.spring.api.DemoService", builder.build()); + } + + @Test + public void testServiceAnnotation() { + Service service = AnnotationUtils.getAnnotation(ServiceBeanNameBuilderTest.class, Service.class); + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, INTERFACE_CLASS, environment); + Assert.assertEquals(BEAN_NAME, + builder.build()); + } + + @Test + public void testReferenceAnnotation() { + Reference reference = AnnotationUtils.getAnnotation(ReflectionUtils.findField(ServiceBeanNameBuilderTest.class, "INTERFACE_CLASS"), Reference.class); + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, INTERFACE_CLASS, environment); + Assert.assertEquals(BEAN_NAME, + builder.build()); + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/YamlPropertySourceFactory.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/YamlPropertySourceFactory.java new file mode 100644 index 00000000000..c9b44c94ad1 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/YamlPropertySourceFactory.java @@ -0,0 +1,76 @@ +/* + * 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.config; + +import org.springframework.beans.factory.config.YamlProcessor; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.core.io.support.EncodedResource; +import org.springframework.core.io.support.PropertySourceFactory; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.nodes.Tag; +import org.yaml.snakeyaml.representer.Representer; +import org.yaml.snakeyaml.resolver.Resolver; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; +import java.util.regex.Pattern; + +/** + * YAML {@link PropertySourceFactory} implementation, some source code is copied Spring Boot + * org.springframework.boot.env.YamlPropertySourceLoader , see {@link #createYaml()} and {@link #process()} + * + * @since 2.6.5 + */ +public class YamlPropertySourceFactory extends YamlProcessor implements PropertySourceFactory { + + @Override + public PropertySource createPropertySource(String name, EncodedResource resource) throws IOException { + setResources(resource.getResource()); + return new MapPropertySource(name, process()); + } + + @Override + protected Yaml createYaml() { + return new Yaml(new StrictMapAppenderConstructor(), new Representer(), + new DumperOptions(), new Resolver() { + @Override + public void addImplicitResolver(Tag tag, Pattern regexp, + String first) { + if (tag == Tag.TIMESTAMP) { + return; + } + super.addImplicitResolver(tag, regexp, first); + } + }); + } + + public Map process() { + final Map result = new LinkedHashMap(); + process(new MatchCallback() { + @Override + public void process(Properties properties, Map map) { + result.putAll(getFlattenedMap(map)); + } + }); + return result; + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/YamlPropertySourceFactoryTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/YamlPropertySourceFactoryTest.java new file mode 100644 index 00000000000..a9861d33c1b --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/YamlPropertySourceFactoryTest.java @@ -0,0 +1,71 @@ +/* + * 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.config; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * {@link YamlPropertySourceFactory} Test + * + * @since 2.6.5 + */ +@RunWith(SpringRunner.class) +@PropertySource(name = "yaml-source", value = {"classpath:/META-INF/dubbo.yml"}, factory = YamlPropertySourceFactory.class) +@Configuration +@ContextConfiguration(classes = YamlPropertySourceFactoryTest.class) +public class YamlPropertySourceFactoryTest { + + @Autowired + private Environment environment; + + @Value("${dubbo.consumer.default}") + private Boolean isDefault; + + @Value("${dubbo.consumer.client}") + private String client; + + @Value("${dubbo.consumer.threadpool}") + private String threadPool; + + @Value("${dubbo.consumer.corethreads}") + private Integer coreThreads; + + @Value("${dubbo.consumer.threads}") + private Integer threads; + + @Value("${dubbo.consumer.queues}") + private Integer queues; + + @Test + public void testProperty() { + Assert.assertEquals(isDefault, environment.getProperty("dubbo.consumer.default", Boolean.class)); + Assert.assertEquals(client, environment.getProperty("dubbo.consumer.client", String.class)); + Assert.assertEquals(threadPool, environment.getProperty("dubbo.consumer.threadpool", String.class)); + Assert.assertEquals(coreThreads, environment.getProperty("dubbo.consumer.corethreads", Integer.class)); + Assert.assertEquals(threads, environment.getProperty("dubbo.consumer.threads", Integer.class)); + Assert.assertEquals(queues, environment.getProperty("dubbo.consumer.queues", Integer.class)); + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrarTest.java index a5e8e682828..24f5bebccd3 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrarTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrarTest.java @@ -17,6 +17,7 @@ package org.apache.dubbo.config.spring.context.annotation; import org.apache.dubbo.config.ApplicationConfig; + 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/org/apache/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java index 93c50d720f2..aaef1a0275b 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java @@ -17,6 +17,7 @@ package org.apache.dubbo.config.spring.context.annotation; import org.apache.dubbo.config.ApplicationConfig; + 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/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java index a1242337c60..980d0a83002 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java @@ -20,6 +20,7 @@ import org.apache.dubbo.config.ModuleConfig; import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.RegistryConfig; + import org.junit.After; import org.junit.Assert; import org.junit.Before; 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 1b85aa2190b..b52864c3b69 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 @@ -23,6 +23,7 @@ import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.ProviderConfig; import org.apache.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/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java index 85b8b71ac29..246e9ecdb77 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java @@ -48,26 +48,28 @@ */ public class EnableDubboTest { + private AnnotationConfigApplicationContext context; + @Before public void setUp() { ConfigManager.getInstance().clear(); + context = new AnnotationConfigApplicationContext(); } @After public void tearDown() { ConfigManager.getInstance().clear(); + context.close(); } @Test - public void test() { - - AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext(); + public void testProvider() { - providerContext.register(TestProviderConfiguration.class); + context.register(TestProviderConfiguration.class); - providerContext.refresh(); + context.refresh(); - DemoService demoService = providerContext.getBean(DemoService.class); + DemoService demoService = context.getBean(DemoService.class); String value = demoService.sayName("Mercy"); @@ -81,21 +83,24 @@ public void test() { // Test @Transactional is present or not Assert.assertNotNull(findAnnotation(beanClass, Transactional.class)); - AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(); + } - consumerContext.register(TestConsumerConfiguration.class); + @Test + public void testConsumer() { - consumerContext.refresh(); + context.register(TestProviderConfiguration.class, TestConsumerConfiguration.class); - TestConsumerConfiguration consumerConfiguration = consumerContext.getBean(TestConsumerConfiguration.class); + context.refresh(); - demoService = consumerConfiguration.getDemoService(); + TestConsumerConfiguration consumerConfiguration = context.getBean(TestConsumerConfiguration.class); - value = demoService.sayName("Mercy"); + DemoService demoService = consumerConfiguration.getDemoService(); + + String value = demoService.sayName("Mercy"); Assert.assertEquals("Hello,Mercy", value); - TestConsumerConfiguration.Child child = consumerContext.getBean(TestConsumerConfiguration.Child.class); + TestConsumerConfiguration.Child child = context.getBean(TestConsumerConfiguration.Child.class); // From Child @@ -127,21 +132,17 @@ public void test() { Assert.assertEquals("Hello,Mercy", value); - // Test dubbo-annotation-consumer2 bean presentation - RegistryConfig registryConfig = consumerContext.getBean("my-registry2", RegistryConfig.class); + // Test my-registry2 bean presentation + RegistryConfig registryConfig = context.getBean("my-registry2", RegistryConfig.class); // Test multiple binding Assert.assertEquals("N/A", registryConfig.getAddress()); - providerContext.close(); - consumerContext.close(); - - } @EnableDubbo(scanBasePackages = "org.apache.dubbo.config.spring.context.annotation.provider") @ComponentScan(basePackages = "org.apache.dubbo.config.spring.context.annotation.provider") - @PropertySource("META-INF/dubbo-provider.properties") + @PropertySource("classpath:/META-INF/dubbo-provider.properties") @EnableTransactionManagement public static class TestProviderConfiguration { diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/ConsumerConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/ConsumerConfiguration.java index 2c07d5ba9aa..c12d4d3bab1 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/ConsumerConfiguration.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/ConsumerConfiguration.java @@ -36,15 +36,15 @@ public class ConsumerConfiguration { /** * Current application configuration, to replace XML config: * - * <dubbo:application name="dubbo-annotation-consumer"/> + * <dubbo:application name="dubbo-demo-application"/> * * * @return {@link ApplicationConfig} Bean */ - @Bean("dubbo-annotation-test") + @Bean("dubbo-demo-application") public ApplicationConfig applicationConfig() { ApplicationConfig applicationConfig = new ApplicationConfig(); - applicationConfig.setName("dubbo-annotation-test"); + applicationConfig.setName("dubbo-demo-application"); return applicationConfig; } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java index d6ed2bd55f3..231754501f8 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java @@ -30,11 +30,11 @@ * @since 2.5.7 */ @EnableDubbo(scanBasePackageClasses = TestConsumerConfiguration.class, multipleConfig = true) -@PropertySource("META-INF/dubbo-consumer.properties") +@PropertySource("classpath:/META-INF/dubbb-consumer.properties") @EnableTransactionManagement public class TestConsumerConfiguration { - @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-annotation-test") + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-demo-application") private DemoService demoService; public DemoService getDemoService() { @@ -53,7 +53,7 @@ public TestConsumerConfiguration.Child c() { public static abstract class Ancestor { - @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-annotation-test") + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-demo-application") private DemoService demoServiceFromAncestor; public DemoService getDemoServiceFromAncestor() { @@ -73,7 +73,7 @@ public DemoService getDemoServiceFromParent() { return demoServiceFromParent; } - @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-annotation-test") + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-demo-application") public void setDemoServiceFromParent(DemoService demoServiceFromParent) { this.demoServiceFromParent = demoServiceFromParent; } @@ -82,7 +82,7 @@ public void setDemoServiceFromParent(DemoService demoServiceFromParent) { public static class Child extends TestConsumerConfiguration.Parent { - @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-annotation-test") + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-demo-application") private DemoService demoServiceFromChild; public DemoService getDemoServiceFromChild() { diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DefaultHelloService.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DefaultHelloService.java index bb5c7fd4c17..f7923644095 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DefaultHelloService.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DefaultHelloService.java @@ -17,6 +17,7 @@ package org.apache.dubbo.config.spring.context.annotation.provider; import org.apache.dubbo.config.spring.api.HelloService; + import org.springframework.stereotype.Service; /** 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 1b21369f0f7..eb12225588f 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 @@ -18,6 +18,7 @@ import org.apache.dubbo.config.spring.api.Box; import org.apache.dubbo.config.spring.api.DemoService; + import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java index abac294ae8d..d168af8bc2b 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java @@ -31,22 +31,22 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; @DubboComponentScan(basePackages = "org.apache.dubbo.config.spring.context.annotation.provider") -@PropertySource("META-INF/default.properties") +@PropertySource("classpath:/META-INF/default.properties") @EnableTransactionManagement public class ProviderConfiguration { /** * Current application configuration, to replace XML config: * - * <dubbo:application name="dubbo-annotation-provider"/> + * <dubbo:application name="dubbo-demo-application"/> * * * @return {@link ApplicationConfig} Bean */ - @Bean("dubbo-annotation-test") + @Bean("dubbo-demo-application") public ApplicationConfig applicationConfig() { ApplicationConfig applicationConfig = new ApplicationConfig(); - applicationConfig.setName("dubbo-annotation-test"); + applicationConfig.setName("dubbo-demo-application"); return applicationConfig; } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboComponentScanRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboComponentScanRegistrarTest.java new file mode 100644 index 00000000000..fd26a0ee3ee --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboComponentScanRegistrarTest.java @@ -0,0 +1,116 @@ +/* + * 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.context.annotation; + +import org.apache.dubbo.config.spring.api.DemoService; +import org.apache.dubbo.config.spring.context.annotation.DubboComponentScanRegistrar; +import org.apache.dubbo.config.spring.context.annotation.consumer.ConsumerConfiguration; +import org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl; +import org.apache.dubbo.config.spring.context.annotation.provider.ProviderConfiguration; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.aop.support.AopUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.transaction.annotation.Transactional; + +import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; + +/** + * {@link DubboComponentScanRegistrar} Test + * + * @since 2.5.8 + */ +public class DubboComponentScanRegistrarTest { + + @Test + public void test() { + + AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext(); + + providerContext.register(ProviderConfiguration.class); + + providerContext.refresh(); + + DemoService demoService = providerContext.getBean(DemoService.class); + + String value = demoService.sayName("Mercy"); + + Assert.assertEquals("Hello,Mercy", value); + + Class beanClass = AopUtils.getTargetClass(demoService); + + // DemoServiceImpl with @Transactional + Assert.assertEquals(DemoServiceImpl.class, beanClass); + + // Test @Transactional is present or not + Assert.assertNotNull(findAnnotation(beanClass, Transactional.class)); + + AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(); + + consumerContext.register(ConsumerConfiguration.class); + + consumerContext.refresh(); + + ConsumerConfiguration consumerConfiguration = consumerContext.getBean(ConsumerConfiguration.class); + + demoService = consumerConfiguration.getDemoService(); + + value = demoService.sayName("Mercy"); + + Assert.assertEquals("Hello,Mercy", value); + + ConsumerConfiguration.Child child = consumerContext.getBean(ConsumerConfiguration.Child.class); + + // From Child + + demoService = child.getDemoServiceFromChild(); + + Assert.assertNotNull(demoService); + + value = demoService.sayName("Mercy"); + + Assert.assertEquals("Hello,Mercy", value); + + // From Parent + + demoService = child.getDemoServiceFromParent(); + + Assert.assertNotNull(demoService); + + value = demoService.sayName("Mercy"); + + Assert.assertEquals("Hello,Mercy", value); + + // From Ancestor + + demoService = child.getDemoServiceFromAncestor(); + + Assert.assertNotNull(demoService); + + value = demoService.sayName("Mercy"); + + Assert.assertEquals("Hello,Mercy", value); + + providerContext.close(); + consumerContext.close(); + + + } + + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigBindingRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigBindingRegistrarTest.java new file mode 100644 index 00000000000..7ec73df6129 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigBindingRegistrarTest.java @@ -0,0 +1,88 @@ +/* + * 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.context.annotation; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar; +import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfigBinding; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.PropertySource; + +/** + * {@link DubboConfigBindingRegistrar} + * + * @since 2.5.8 + */ +public class DubboConfigBindingRegistrarTest { + + @Test + public void testRegisterBeanDefinitionsForSingle() { + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + + context.register(TestApplicationConfig.class); + + context.refresh(); + + ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); + + Assert.assertEquals("dubbo-demo-application", applicationConfig.getName()); + + + } + + @Test + public void testRegisterBeanDefinitionsForMultiple() { + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + + context.register(TestMultipleApplicationConfig.class); + + context.refresh(); + + ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); + + Assert.assertEquals("dubbo-demo-application", applicationConfig.getName()); + + applicationConfig = context.getBean("applicationBean2", ApplicationConfig.class); + + Assert.assertEquals("dubbo-demo-application2", applicationConfig.getName()); + + applicationConfig = context.getBean("applicationBean3", ApplicationConfig.class); + + Assert.assertEquals("dubbo-demo-application3", applicationConfig.getName()); + + + } + + @EnableDubboConfigBinding(prefix = "${application.prefixes}", type = ApplicationConfig.class, multiple = true) + @PropertySource("META-INF/config.properties") + private static class TestMultipleApplicationConfig { + + } + + @EnableDubboConfigBinding(prefix = "${application.prefix}", type = ApplicationConfig.class) + @PropertySource("META-INF/config.properties") + private static class TestApplicationConfig { + + } + + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigBindingsRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigBindingsRegistrarTest.java new file mode 100644 index 00000000000..6cae40dd5af --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigBindingsRegistrarTest.java @@ -0,0 +1,63 @@ +/* + * 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.context.annotation; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingsRegistrar; +import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfigBinding; +import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfigBindings; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.PropertySource; + +/** + * {@link DubboConfigBindingsRegistrar} Test + * + * @since DubboConfigBindingsRegistrar + */ +public class DubboConfigBindingsRegistrarTest { + + @Test + public void test() { + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + + context.register(TestConfig.class); + + context.refresh(); + + ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); + + Assert.assertEquals("dubbo-demo-application", applicationConfig.getName()); + + Assert.assertEquals(2, context.getBeansOfType(ApplicationConfig.class).size()); + + } + + + @EnableDubboConfigBindings({ + @EnableDubboConfigBinding(prefix = "${application.prefix}", type = ApplicationConfig.class), + @EnableDubboConfigBinding(prefix = "dubbo.applications.applicationBean", type = ApplicationConfig.class) + }) + @PropertySource("META-INF/config.properties") + private static class TestConfig { + + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigConfigurationTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigConfigurationTest.java new file mode 100644 index 00000000000..d75bac219e1 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigConfigurationTest.java @@ -0,0 +1,99 @@ +/* + * 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.context.annotation; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ModuleConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.spring.context.annotation.DubboConfigConfiguration; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.core.io.support.ResourcePropertySource; + +import java.io.IOException; + +/** + * {@link DubboConfigConfiguration} Test + * + * @since 2.5.8 + */ +public class DubboConfigConfigurationTest { + + private AnnotationConfigApplicationContext context; + + @Before + public void before() throws IOException { + + context = new AnnotationConfigApplicationContext(); + ResourcePropertySource propertySource = new ResourcePropertySource("META-INF/config.properties"); + context.getEnvironment().getPropertySources().addFirst(propertySource); + + } + + @After + public void after() { + context.close(); + } + + @Test + public void testSingle() throws IOException { + + context.register(DubboConfigConfiguration.Single.class); + context.refresh(); + + // application + ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); + Assert.assertEquals("dubbo-demo-application", applicationConfig.getName()); + + // module + ModuleConfig moduleConfig = context.getBean("moduleBean", ModuleConfig.class); + Assert.assertEquals("dubbo-demo-module", moduleConfig.getName()); + + // registry + RegistryConfig registryConfig = context.getBean(RegistryConfig.class); + Assert.assertEquals("zookeeper://192.168.99.100:32770", registryConfig.getAddress()); + + // protocol + ProtocolConfig protocolConfig = context.getBean(ProtocolConfig.class); + Assert.assertEquals("dubbo", protocolConfig.getName()); + Assert.assertEquals(Integer.valueOf(20880), protocolConfig.getPort()); + } + + @Test + public void testMultiple() { + + context.register(DubboConfigConfiguration.Multiple.class); + context.refresh(); + + // application + ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); + Assert.assertEquals("dubbo-demo-application", applicationConfig.getName()); + + ApplicationConfig applicationBean2 = context.getBean("applicationBean2", ApplicationConfig.class); + Assert.assertEquals("dubbo-demo-application2", applicationBean2.getName()); + + ApplicationConfig applicationBean3 = context.getBean("applicationBean3", ApplicationConfig.class); + Assert.assertEquals("dubbo-demo-application3", applicationBean3.getName()); + + } + +} 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 new file mode 100644 index 00000000000..41306beb733 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/EnableDubboConfigTest.java @@ -0,0 +1,109 @@ +/* + * 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.context.annotation; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ConsumerConfig; +import org.apache.dubbo.config.ModuleConfig; +import org.apache.dubbo.config.MonitorConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.ProviderConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfig; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.PropertySource; + +/** + * {@link EnableDubboConfig} Test + * + * @since 2.5.8 + */ +public class EnableDubboConfigTest { + + @Test + public void testSingle() { + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(TestConfig.class); + context.refresh(); + + // application + ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); + Assert.assertEquals("dubbo-demo-application", applicationConfig.getName()); + + // module + ModuleConfig moduleConfig = context.getBean("moduleBean", ModuleConfig.class); + Assert.assertEquals("dubbo-demo-module", moduleConfig.getName()); + + // registry + RegistryConfig registryConfig = context.getBean(RegistryConfig.class); + Assert.assertEquals("zookeeper://192.168.99.100:32770", registryConfig.getAddress()); + + // protocol + ProtocolConfig protocolConfig = context.getBean(ProtocolConfig.class); + Assert.assertEquals("dubbo", protocolConfig.getName()); + Assert.assertEquals(Integer.valueOf(20880), protocolConfig.getPort()); + + // monitor + MonitorConfig monitorConfig = context.getBean(MonitorConfig.class); + Assert.assertEquals("zookeeper://127.0.0.1:32770", monitorConfig.getAddress()); + + // provider + ProviderConfig providerConfig = context.getBean(ProviderConfig.class); + Assert.assertEquals("127.0.0.1", providerConfig.getHost()); + + + // consumer + ConsumerConfig consumerConfig = context.getBean(ConsumerConfig.class); + Assert.assertEquals("netty", consumerConfig.getClient()); + + } + + @Test + public void testMultiple() { + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(TestMultipleConfig.class); + context.refresh(); + + // application + ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); + Assert.assertEquals("dubbo-demo-application", applicationConfig.getName()); + + ApplicationConfig applicationBean2 = context.getBean("applicationBean2", ApplicationConfig.class); + Assert.assertEquals("dubbo-demo-application2", applicationBean2.getName()); + + ApplicationConfig applicationBean3 = context.getBean("applicationBean3", ApplicationConfig.class); + Assert.assertEquals("dubbo-demo-application3", applicationBean3.getName()); + + } + + @EnableDubboConfig(multiple = true) + @PropertySource("META-INF/config.properties") + private static class TestMultipleConfig { + + } + + @EnableDubboConfig + @PropertySource("META-INF/config.properties") + private static class TestConfig { + + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/EnableDubboTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/EnableDubboTest.java new file mode 100644 index 00000000000..1366a35d252 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/EnableDubboTest.java @@ -0,0 +1,162 @@ +/* + * 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.context.annotation; + +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.spring.api.DemoService; +import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; +import org.apache.dubbo.config.spring.context.annotation.consumer.test.TestConsumerConfiguration; +import org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +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.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionException; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.transaction.annotation.Transactional; + +import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; + +/** + * {@link EnableDubbo} Test + * + * @since 2.5.8 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = {EnableDubboTest.class}) +@TestPropertySource(locations = "classpath:/META-INF/dubbb-provider.properties", + properties = "demo.service.version = 2.5.7") +@EnableDubbo(scanBasePackages = "org.apache.dubbo.config.spring.context.annotation.provider") +@ComponentScan(basePackages = "org.apache.dubbo.config.spring.context.annotation.provider") +@EnableTransactionManagement +public class EnableDubboTest { + + @Autowired + private ApplicationContext providerContext; + + @Test + public void test() { + + DemoService demoService = providerContext.getBean(DemoService.class); + + String value = demoService.sayName("Mercy"); + + Assert.assertEquals("Hello,Mercy", value); + + Class beanClass = AopUtils.getTargetClass(demoService); + + // DemoServiceImpl with @Transactional + Assert.assertEquals(DemoServiceImpl.class, beanClass); + + // Test @Transactional is present or not + Assert.assertNotNull(findAnnotation(beanClass, Transactional.class)); + + AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(TestConsumerConfiguration.class); + + TestConsumerConfiguration consumerConfiguration = consumerContext.getBean(TestConsumerConfiguration.class); + + demoService = consumerConfiguration.getDemoService(); + + value = demoService.sayName("Mercy"); + + Assert.assertEquals("Hello,Mercy", value); + + TestConsumerConfiguration.Child child = consumerContext.getBean(TestConsumerConfiguration.Child.class); + + // From Child + + demoService = child.getDemoServiceFromChild(); + + Assert.assertNotNull(demoService); + + value = demoService.sayName("Mercy"); + + Assert.assertEquals("Hello,Mercy", value); + + // From Parent + + demoService = child.getDemoServiceFromParent(); + + Assert.assertNotNull(demoService); + + value = demoService.sayName("Mercy"); + + Assert.assertEquals("Hello,Mercy", value); + + // From Ancestor + + demoService = child.getDemoServiceFromAncestor(); + + Assert.assertNotNull(demoService); + + value = demoService.sayName("Mercy"); + + Assert.assertEquals("Hello,Mercy", value); + + // Test my-registry2 bean presentation + RegistryConfig registryConfig = consumerContext.getBean("my-registry2", RegistryConfig.class); + + // Test multiple binding + Assert.assertEquals("N/A", registryConfig.getAddress()); + + } + + @EnableDubbo(scanBasePackages = "org.apache.dubbo.config.spring.context.annotation.provider") + @ComponentScan(basePackages = "org.apache.dubbo.config.spring.context.annotation.provider") + @PropertySource("classpath:/META-INF/dubbb-provider.properties") + @EnableTransactionManagement + public static class TestProviderConfiguration { + + @Primary + @Bean + public PlatformTransactionManager platformTransactionManager() { + return new PlatformTransactionManager() { + + @Override + public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException { + return null; + } + + @Override + public void commit(TransactionStatus status) throws TransactionException { + + } + + @Override + public void rollback(TransactionStatus status) throws TransactionException { + + } + }; + } + } + + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/consumer/ConsumerConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/consumer/ConsumerConfiguration.java new file mode 100644 index 00000000000..04866986197 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/consumer/ConsumerConfiguration.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.config.spring.context.context.annotation.consumer; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.spring.api.DemoService; +import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +@Configuration("consumerConfiguration") +@DubboComponentScan( + basePackageClasses = ConsumerConfiguration.class +) +@PropertySource("META-INF/default.properties") +public class ConsumerConfiguration { + + /** + * Current application configuration, to replace XML config: + * + * <dubbo:application name="dubbo-demo-application"/> + * + * + * @return {@link ApplicationConfig} Bean + */ + @Bean("dubbo-demo-application") + public ApplicationConfig applicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("dubbo-demo-application"); + return applicationConfig; + } + + /** + * Current registry center configuration, to replace XML config: + * + * <dubbo:registry address="N/A"/> + * + * + * @return {@link RegistryConfig} Bean + */ + @Bean + public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress("N/A"); + return registryConfig; + } + + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345") + private DemoService demoService; + + public DemoService getDemoService() { + return demoService; + } + + public void setDemoService(DemoService demoService) { + this.demoService = demoService; + } + + + @Bean + public Child c() { + return new Child(); + } + + public static abstract class Ancestor { + + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345") + private DemoService demoServiceFromAncestor; + + public DemoService getDemoServiceFromAncestor() { + return demoServiceFromAncestor; + } + + public void setDemoServiceFromAncestor(DemoService demoServiceFromAncestor) { + this.demoServiceFromAncestor = demoServiceFromAncestor; + } + } + + public static abstract class Parent extends Ancestor { + + private DemoService demoServiceFromParent; + + public DemoService getDemoServiceFromParent() { + return demoServiceFromParent; + } + + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345") + public void setDemoServiceFromParent(DemoService demoServiceFromParent) { + this.demoServiceFromParent = demoServiceFromParent; + } + + } + + public static class Child extends Parent { + + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345") + private DemoService demoServiceFromChild; + + public DemoService getDemoServiceFromChild() { + return demoServiceFromChild; + } + + public void setDemoServiceFromChild(DemoService demoServiceFromChild) { + this.demoServiceFromChild = demoServiceFromChild; + } + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/consumer/test/TestConsumerConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/consumer/test/TestConsumerConfiguration.java new file mode 100644 index 00000000000..dc41c614cd8 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/consumer/test/TestConsumerConfiguration.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.config.spring.context.context.annotation.consumer.test; + +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.spring.api.DemoService; +import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.PropertySource; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * Test Consumer Configuration + * + * @since 2.5.7 + */ +@EnableDubbo(scanBasePackageClasses = TestConsumerConfiguration.class, multipleConfig = true) +@PropertySource("META-INF/dubbb-consumer.properties") +@EnableTransactionManagement +public class TestConsumerConfiguration { + + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-demo-application") + private DemoService demoService; + + public DemoService getDemoService() { + return demoService; + } + + public void setDemoService(DemoService demoService) { + this.demoService = demoService; + } + + + @Bean + public TestConsumerConfiguration.Child c() { + return new TestConsumerConfiguration.Child(); + } + + public static abstract class Ancestor { + + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-demo-application") + private DemoService demoServiceFromAncestor; + + public DemoService getDemoServiceFromAncestor() { + return demoServiceFromAncestor; + } + + public void setDemoServiceFromAncestor(DemoService demoServiceFromAncestor) { + this.demoServiceFromAncestor = demoServiceFromAncestor; + } + } + + public static abstract class Parent extends TestConsumerConfiguration.Ancestor { + + private DemoService demoServiceFromParent; + + public DemoService getDemoServiceFromParent() { + return demoServiceFromParent; + } + + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-demo-application") + public void setDemoServiceFromParent(DemoService demoServiceFromParent) { + this.demoServiceFromParent = demoServiceFromParent; + } + + } + + public static class Child extends TestConsumerConfiguration.Parent { + + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-demo-application") + private DemoService demoServiceFromChild; + + public DemoService getDemoServiceFromChild() { + return demoServiceFromChild; + } + + public void setDemoServiceFromChild(DemoService demoServiceFromChild) { + this.demoServiceFromChild = demoServiceFromChild; + } + } +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToStringConverter.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/DefaultHelloService.java similarity index 59% rename from dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToStringConverter.java rename to dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/DefaultHelloService.java index 7cd6e7124aa..b484d26a931 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToStringConverter.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/DefaultHelloService.java @@ -14,24 +14,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.config.spring.convert.converter; +package org.apache.dubbo.config.spring.context.context.annotation.provider; -import org.springframework.core.convert.converter.Converter; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; +import org.apache.dubbo.config.spring.api.HelloService; +import org.springframework.stereotype.Service; /** - * String[] to String {@ConditionalGenericConverter} + * Default {@link HelloService} annotation with Spring's {@link Service} + * and Dubbo's {@link org.apache.dubbo.config.annotation.Service} * - * @see StringUtils#arrayToCommaDelimitedString(Object[]) - * @since 2.5.11 + * @since TODO */ -public class StringArrayToStringConverter implements Converter { +@Service +@org.apache.dubbo.config.annotation.Service +public class DefaultHelloService implements HelloService { @Override - public String convert(String[] source) { - return ObjectUtils.isEmpty(source) ? null : StringUtils.arrayToCommaDelimitedString(source); + public String sayHello(String name) { + return "Greeting, " + name; } } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/DemoServiceImpl.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/DemoServiceImpl.java new file mode 100644 index 00000000000..155bd2a5539 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/DemoServiceImpl.java @@ -0,0 +1,55 @@ +/* + * 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.context.annotation.provider; + +import org.apache.dubbo.config.spring.api.Box; +import org.apache.dubbo.config.spring.api.DemoService; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + + +/** + * {@link DemoService} Service implementation + * + * @since 2.5.8 + */ +@org.apache.dubbo.config.annotation.Service( + version = "${demo.service.version}", + application = "${demo.service.application}", + protocol = "${demo.service.protocol}", + registry = "${demo.service.registry}" +) +@Service +@Transactional +public class DemoServiceImpl implements DemoService { + + @Override + public String sayName(String name) { + return "Hello," + name; + } + + @Override + public Box getBox() { + return new Box() { + @Override + public String getName() { + return "MyBox"; + } + }; + } +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToMapConverter.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/HelloServiceImpl.java similarity index 58% rename from dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToMapConverter.java rename to dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/HelloServiceImpl.java index a2e4790919b..10b00a8f5b3 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToMapConverter.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/HelloServiceImpl.java @@ -14,26 +14,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.config.spring.convert.converter; +package org.apache.dubbo.config.spring.context.context.annotation.provider; -import org.apache.dubbo.common.utils.CollectionUtils; - -import org.springframework.core.convert.converter.Converter; -import org.springframework.util.ObjectUtils; - -import java.util.Map; +import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.config.spring.api.HelloService; /** - * {@link String}[] to {@link Map} {@link Converter} + * {@link HelloService} Implementation just annotating Dubbo's {@link Service} * - * @see CollectionUtils#toStringMap(String[]) - * @since 2.5.11 + * @since 2.5.9 */ -public class StringArrayToMapConverter implements Converter> { +@Service(interfaceName = "org.apache.dubbo.config.spring.api.HelloService") +public class HelloServiceImpl implements HelloService { @Override - public Map convert(String[] source) { - return ObjectUtils.isEmpty(source) ? null : CollectionUtils.toStringMap(source); + public String sayHello(String name) { + return "Hello, " + name; } - } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/ProviderConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/ProviderConfiguration.java new file mode 100644 index 00000000000..c77322848d6 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/ProviderConfiguration.java @@ -0,0 +1,107 @@ +/* + * 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.context.annotation.provider; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.PropertySource; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionException; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@DubboComponentScan(basePackages = "org.apache.dubbo.config.spring.context.annotation.provider") +@PropertySource("META-INF/default.properties") +@EnableTransactionManagement +public class ProviderConfiguration { + + /** + * Current application configuration, to replace XML config: + * + * <dubbo:application name="dubbo-demo-application"/> + * + * + * @return {@link ApplicationConfig} Bean + */ + @Bean("dubbo-demo-application") + public ApplicationConfig applicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("dubbo-demo-application"); + return applicationConfig; + } + + /** + * Current registry center configuration, to replace XML config: + * + * <dubbo:registry id="my-registry" address="N/A"/> + * + * + * @return {@link RegistryConfig} Bean + */ + @Bean("my-registry") + public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress("N/A"); + return registryConfig; + } + + /** + * Current protocol configuration, to replace XML config: + * + * <dubbo:protocol name="dubbo" port="12345"/> + * + * + * @return {@link ProtocolConfig} Bean + */ + @Bean("dubbo") + public ProtocolConfig protocolConfig() { + ProtocolConfig protocolConfig = new ProtocolConfig(); + protocolConfig.setName("dubbo"); + protocolConfig.setPort(12345); + return protocolConfig; + } + + @Primary + @Bean + public PlatformTransactionManager platformTransactionManager() { + return new PlatformTransactionManager() { + + @Override + public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException { + return null; + } + + @Override + public void commit(TransactionStatus status) throws TransactionException { + + } + + @Override + public void rollback(TransactionStatus status) throws TransactionException { + + } + }; + } + +} + diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/properties/DefaultDubboConfigBinderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/properties/DefaultDubboConfigBinderTest.java new file mode 100644 index 00000000000..1caddb0b31b --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/properties/DefaultDubboConfigBinderTest.java @@ -0,0 +1,94 @@ +/* + * 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.context.properties; + + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ConsumerConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.spring.beans.factory.config.YamlPropertySourceFactory; +import org.apache.dubbo.config.spring.context.properties.DefaultDubboConfigBinder; +import org.apache.dubbo.config.spring.context.properties.DubboConfigBinder; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@TestPropertySource(locations = "classpath:/dubbo.properties") +@PropertySource(name = "yaml-source", value = {"classpath:/META-INF/dubbo.yml"}, factory = YamlPropertySourceFactory.class) +@Configuration +@ContextConfiguration(classes = {DefaultDubboConfigBinder.class, DefaultDubboConfigBinderTest.class}) +public class DefaultDubboConfigBinderTest { + + @Autowired + private DubboConfigBinder dubboConfigBinder; + + @Value("${dubbo.consumer.default}") + private Boolean isDefault; + + @Value("${dubbo.consumer.client}") + private String client; + + @Value("${dubbo.consumer.threadpool}") + private String threadPool; + + @Value("${dubbo.consumer.corethreads}") + private Integer coreThreads; + + @Value("${dubbo.consumer.threads}") + private Integer threads; + + @Value("${dubbo.consumer.queues}") + private Integer queues; + + @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()); + + ConsumerConfig consumerConfig = new ConsumerConfig(); + dubboConfigBinder.bind("dubbo.consumer", consumerConfig); + + Assert.assertEquals(isDefault, consumerConfig.isDefault()); + Assert.assertEquals(client, consumerConfig.getClient()); + Assert.assertEquals(threadPool, consumerConfig.getThreadpool()); + Assert.assertEquals(coreThreads, consumerConfig.getCorethreads()); + Assert.assertEquals(threads, consumerConfig.getThreads()); + Assert.assertEquals(queues, consumerConfig.getQueues()); + } +} + diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinderTest.java index f6e741d17fc..c5bf751ee04 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinderTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinderTest.java @@ -20,6 +20,7 @@ import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.RegistryConfig; + import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToMapConverterTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToMapConverterTest.java deleted file mode 100644 index 58efd7ad5cf..00000000000 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToMapConverterTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.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/org/apache/dubbo/config/spring/extension/SpringExtensionFactoryTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/extension/SpringExtensionFactoryTest.java index 134b50bcb58..b37bccda9c4 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/extension/SpringExtensionFactoryTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/extension/SpringExtensionFactoryTest.java @@ -20,8 +20,8 @@ import org.apache.dubbo.config.spring.api.HelloService; import org.apache.dubbo.config.spring.impl.DemoServiceImpl; import org.apache.dubbo.config.spring.impl.HelloServiceImpl; - import org.apache.dubbo.rpc.Protocol; + import org.junit.After; import org.junit.Assert; import org.junit.Before; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/status/DataSourceStatusCheckerTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/status/DataSourceStatusCheckerTest.java index c82fd4af615..3bf18690523 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/status/DataSourceStatusCheckerTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/status/DataSourceStatusCheckerTest.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.status.Status; import org.apache.dubbo.config.spring.ServiceBean; import org.apache.dubbo.config.spring.extension.SpringExtensionFactory; + import org.junit.After; import org.junit.Before; import org.junit.Test; 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 66155e17135..8f62ed2423f 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 @@ -19,6 +19,7 @@ import org.apache.dubbo.common.status.Status; import org.apache.dubbo.config.spring.ServiceBean; import org.apache.dubbo.config.spring.extension.SpringExtensionFactory; + import org.junit.After; import org.junit.Before; import org.junit.Test; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/util/PropertySourcesUtilsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/util/PropertySourcesUtilsTest.java index 40481317aca..a164bd11c15 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/util/PropertySourcesUtilsTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/util/PropertySourcesUtilsTest.java @@ -39,26 +39,31 @@ public void testGetSubProperties() { MutablePropertySources propertySources = new MutablePropertySources(); Map source = new HashMap(); + Map source2 = new HashMap(); - MapPropertySource propertySource = new MapPropertySource("test", source); + MapPropertySource propertySource = new MapPropertySource("propertySource", source); + MapPropertySource propertySource2 = new MapPropertySource("propertySource2", source2); - propertySources.addFirst(propertySource); + propertySources.addLast(propertySource); + propertySources.addLast(propertySource2); - String KEY_PREFIX = "user"; - String KEY_NAME = "name"; - String KEY_AGE = "age"; - Map result = PropertySourcesUtils.getSubProperties(propertySources, KEY_PREFIX); + Map result = PropertySourcesUtils.getSubProperties(propertySources, "user"); Assert.assertEquals(Collections.emptyMap(), result); - source.put(KEY_PREFIX + "." + KEY_NAME, "Mercy"); - source.put(KEY_PREFIX + "." + KEY_AGE, 31); + source.put("age", "31"); + source.put("user.name", "Mercy"); + source.put("user.age", "${age}"); + + source2.put("user.name", "mercyblitz"); + source2.put("user.age", "32"); Map expected = new HashMap(); - expected.put(KEY_NAME, "Mercy"); - expected.put(KEY_AGE, "31"); + expected.put("name", "Mercy"); + expected.put("age", "31"); + + result = PropertySourcesUtils.getSubProperties(propertySources, "user"); - result = PropertySourcesUtils.getSubProperties(propertySources, KEY_PREFIX); Assert.assertEquals(expected, result); result = PropertySourcesUtils.getSubProperties(propertySources, ""); @@ -69,15 +74,6 @@ public void testGetSubProperties() { Assert.assertEquals(Collections.emptyMap(), result); - source.put(KEY_PREFIX + ".app.name", "${info.name}"); - source.put("info.name", "Hello app"); - - result = PropertySourcesUtils.getSubProperties(propertySources, KEY_PREFIX); - - String appName = result.get("app.name"); - - Assert.assertEquals("Hello app", appName); - } -} +} \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/default.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/default.properties index c717e1b4e5d..101030bba99 100644 --- a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/default.properties +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/default.properties @@ -1,4 +1,4 @@ demo.service.version = 2.5.7 -demo.service.application = dubbo-annotation-test +demo.service.application = dubbo-demo-application demo.service.protocol = dubbo demo.service.registry = my-registry diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbb-consumer.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbb-consumer.properties new file mode 100644 index 00000000000..4583323bbd7 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbb-consumer.properties @@ -0,0 +1,12 @@ +# Dubbo Consumer Properties as an alternative for +# Spring XML Bean definition : META-INF/spring/dubbo-annotation-consumer.xml +demo.service.application = dubbo-demo-application +demo.service.registry = my-registry + +## Dubbo configs binding properties +### +dubbo.applications.dubbo-demo-application.name = dubbo-demo-application + +### +dubbo.registries.my-registry.address = N/A +dubbo.registries.my-registry2.address = N/A \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbb-provider.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbb-provider.properties new file mode 100644 index 00000000000..2ef6638dc9d --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbb-provider.properties @@ -0,0 +1,24 @@ +# Dubbo Provider Properties as an alternative for +# Spring XML Bean definition : META-INF/spring/dubbo-annotation-provider.xml + +## Service Providers' Placeholders for com.alibaba.dubbo.config.spring.context.annotation.provider.DemoServiceImpl + +demo.service.application = dubbo-demo-application +demo.service.protocol = dubbo +demo.service.registry = my-registry + + +## Dubbo configs binding properties + +### +dubbo.application.id = dubbo-demo-application +dubbo.application.name = dubbo-demo-application + +### +dubbo.registry.id = my-registry +dubbo.registry.address = N/A + +### +dubbo.protocol.id = dubbo +dubbo.protocol.name = dubbo +dubbo.protocol.port = 12345 \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-consumer.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-consumer.properties index 6f735a28148..094b709165e 100644 --- a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-consumer.properties +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-consumer.properties @@ -4,9 +4,9 @@ demo.service.application = dubbo-annotation-test demo.service.registry = my-registry ## Dubbo configs binding properties -### +### # In this UT, the provider will be responsible of loading ApplicationConfig. -dubbo.applications.dubbo-annotation-consumer.name = dubbo-annotation-test +dubbo.applications.dubbo-demo-application.name = dubbo-demo-application ### dubbo.registries.my-registry.address = N/A diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-provider.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-provider.properties index a2a3141962b..b676caa9fd7 100644 --- a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-provider.properties +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-provider.properties @@ -3,16 +3,16 @@ ## Service Providers' Placeholders for org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl -demo.service.application = dubbo-annotation-test +demo.service.application = dubbo-demo-application demo.service.protocol = dubbo demo.service.registry = my-registry ## Dubbo configs binding properties -### -dubbo.application.id = dubbo-annotation-test -dubbo.application.name = dubbo-annotation-test +### +dubbo.application.id = dubbo-demo-application +dubbo.application.name = dubbo-demo-application ### dubbo.registry.id = my-registry diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo.yml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo.yml new file mode 100644 index 00000000000..ed0f0ddbc4c --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo.yml @@ -0,0 +1,8 @@ +dubbo: + consumer: + default: false + client: netty + threadpool: cached + corethreads: 1 + threads: 10 + queues: 99 \ No newline at end of file