From 85b0b54b449ce4e45641e8eff71a66478dffbde1 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Fri, 18 Jan 2019 09:27:38 +0800 Subject: [PATCH] Polish apache/incubator-dubbo#3189 Simplify externalized configuration of Dubbo Protocol name --- .../DubboConfigBindingBeanPostProcessor.java | 56 ++++++++++++-- .../DubboConfigBindingRegistrar.java | 10 ++- .../config/DubboConfigBeanCustomizer.java | 46 ++++++++++++ ...DefaultValueDubboConfigBeanCustomizer.java | 75 +++++++++++++++++++ ...bboConfigBindingBeanPostProcessorTest.java | 50 +++++++------ .../annotation/EnableDubboConfigTest.java | 11 ++- .../test/resources/META-INF/config.properties | 4 + 7 files changed, 221 insertions(+), 31 deletions(-) create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/DubboConfigBeanCustomizer.java create mode 100644 dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/NamePropertyDefaultValueDubboConfigBeanCustomizer.java diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java index 46ace143af5..f87be246935 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java @@ -20,9 +20,9 @@ import com.alibaba.dubbo.config.AbstractConfig; import com.alibaba.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar; import com.alibaba.dubbo.config.spring.context.annotation.EnableDubboConfigBinding; +import com.alibaba.dubbo.config.spring.context.config.DubboConfigBeanCustomizer; import com.alibaba.dubbo.config.spring.context.properties.DefaultDubboConfigBinder; import com.alibaba.dubbo.config.spring.context.properties.DubboConfigBinder; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; @@ -30,8 +30,16 @@ import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.env.Environment; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors; + /** * Dubbo Config Binding {@link BeanPostProcessor} * @@ -62,6 +70,8 @@ public class DubboConfigBindingBeanPostProcessor implements BeanPostProcessor, A private boolean ignoreInvalidFields = true; + private List configBeanCustomizers = Collections.emptyList(); + /** * @param prefix the prefix of Configuration Properties * @param beanName the binding Bean Name @@ -80,18 +90,34 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro AbstractConfig dubboConfig = (AbstractConfig) bean; - dubboConfigBinder.bind(prefix, dubboConfig); + bind(prefix, dubboConfig); + + customize(beanName, dubboConfig); - if (log.isInfoEnabled()) { - log.info("The properties of bean [name : " + beanName + "] have been binding by prefix of " + - "configuration properties : " + prefix); - } } return bean; } + private void bind(String prefix, AbstractConfig dubboConfig) { + + dubboConfigBinder.bind(prefix, dubboConfig); + + if (log.isInfoEnabled()) { + log.info("The properties of bean [name : " + beanName + "] have been binding by prefix of " + + "configuration properties : " + prefix); + } + } + + private void customize(String beanName, AbstractConfig dubboConfig) { + + for (DubboConfigBeanCustomizer customizer : configBeanCustomizers) { + customizer.customize(beanName, dubboConfig); + } + + } + public boolean isIgnoreUnknownFields() { return ignoreUnknownFields; } @@ -129,6 +155,14 @@ public void setApplicationContext(ApplicationContext applicationContext) throws @Override public void afterPropertiesSet() throws Exception { + initDubboConfigBinder(); + + initConfigBeanCustomizers(); + + } + + private void initDubboConfigBinder() { + if (dubboConfigBinder == null) { try { dubboConfigBinder = applicationContext.getBean(DubboConfigBinder.class); @@ -146,6 +180,16 @@ public void afterPropertiesSet() throws Exception { } + private void initConfigBeanCustomizers() { + + Collection configBeanCustomizers = + beansOfTypeIncludingAncestors(applicationContext, DubboConfigBeanCustomizer.class).values(); + + this.configBeanCustomizers = new ArrayList(configBeanCustomizers); + + AnnotationAwareOrderComparator.sort(this.configBeanCustomizers); + } + /** * Create {@link DubboConfigBinder} instance. * diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java index 5e1c18ef81a..2f55f2965eb 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java @@ -18,7 +18,7 @@ import com.alibaba.dubbo.config.AbstractConfig; import com.alibaba.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor; - +import com.alibaba.dubbo.config.spring.context.config.NamePropertyDefaultValueDubboConfigBeanCustomizer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.config.BeanDefinition; @@ -41,6 +41,7 @@ import java.util.Map; import java.util.Set; +import static com.alibaba.dubbo.config.spring.util.BeanRegistrar.registerInfrastructureBean; import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties; import static com.alibaba.dubbo.config.spring.util.PropertySourcesUtils.normalizePrefix; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; @@ -107,6 +108,8 @@ private void registerDubboConfigBeans(String prefix, } + registerDubboConfigBeanCustomizers(registry); + } private void registerDubboConfigBean(String beanName, Class configClass, @@ -149,6 +152,11 @@ private void registerDubboConfigBindingBeanPostProcessor(String prefix, String b } + private void registerDubboConfigBeanCustomizers(BeanDefinitionRegistry registry) { + registerInfrastructureBean(registry, "namePropertyDefaultValueDubboConfigBeanCustomizer", + NamePropertyDefaultValueDubboConfigBeanCustomizer.class); + } + @Override public void setEnvironment(Environment environment) { diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/DubboConfigBeanCustomizer.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/DubboConfigBeanCustomizer.java new file mode 100644 index 00000000000..42e1f6a2504 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/DubboConfigBeanCustomizer.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubbo.config.spring.context.config; + +import com.alibaba.dubbo.config.AbstractConfig; +import com.alibaba.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor; +import com.alibaba.dubbo.config.spring.context.properties.DubboConfigBinder; +import org.springframework.context.ApplicationContext; +import org.springframework.core.Ordered; + +/** + * The Bean customizer for {@link AbstractConfig Dubbo Config}. Generally, The subclass will be registered as a Spring + * Bean that is used to {@link #customize(String, AbstractConfig) customize} {@link AbstractConfig Dubbo Config} bean + * after {@link DubboConfigBinder#bind(String, AbstractConfig) its binding}. + *

+ * If There are multiple {@link DubboConfigBeanCustomizer} beans in the Spring {@link ApplicationContext context}, they + * are executed orderly, thus the subclass should be aware to implement the {@link #getOrder()} method. + * + * @see DubboConfigBinder#bind(String, AbstractConfig) + * @see DubboConfigBindingBeanPostProcessor + * @since 2.6.6 + */ +public interface DubboConfigBeanCustomizer extends Ordered { + + /** + * Customize {@link AbstractConfig Dubbo Config Bean} + * + * @param beanName the name of {@link AbstractConfig Dubbo Config Bean} + * @param dubboConfigBean the instance of {@link AbstractConfig Dubbo Config Bean} + */ + void customize(String beanName, AbstractConfig dubboConfigBean); +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/NamePropertyDefaultValueDubboConfigBeanCustomizer.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/NamePropertyDefaultValueDubboConfigBeanCustomizer.java new file mode 100644 index 00000000000..d938218cf71 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/context/config/NamePropertyDefaultValueDubboConfigBeanCustomizer.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.dubbo.config.spring.context.config; + +import com.alibaba.dubbo.config.AbstractConfig; +import org.springframework.util.ReflectionUtils; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.Arrays; + +import static com.alibaba.dubbo.config.spring.util.ObjectUtils.of; +import static org.springframework.beans.BeanUtils.getPropertyDescriptor; + +/** + * {@link DubboConfigBeanCustomizer} for the default value for the "name" property that will be taken bean name + * if absent. + * + * @since 2.6.6 + */ +public class NamePropertyDefaultValueDubboConfigBeanCustomizer implements DubboConfigBeanCustomizer { + + /** + * The name of property that is "name" maybe is absent in target class + */ + private static final String PROPERTY_NAME = "name"; + + @Override + public void customize(String beanName, AbstractConfig dubboConfigBean) { + + PropertyDescriptor propertyDescriptor = getPropertyDescriptor(dubboConfigBean.getClass(), PROPERTY_NAME); + + if (propertyDescriptor != null) { // "name" property is present + + Method getNameMethod = propertyDescriptor.getReadMethod(); + + if (getNameMethod == null) { // if "getName" method is absent + return; + } + + Object propertyValue = ReflectionUtils.invokeMethod(getNameMethod, dubboConfigBean); + + if (propertyValue != null) { // If The return value of "getName" method is not null + return; + } + + Method setNameMethod = propertyDescriptor.getWriteMethod(); + if (setNameMethod != null && getNameMethod != null) { // "setName" and "getName" methods are present + if (Arrays.equals(of(String.class), setNameMethod.getParameterTypes())) { // the param type is String + // set bean name to the value of the "name" property + ReflectionUtils.invokeMethod(setNameMethod, dubboConfigBean, beanName); + } + } + } + } + + @Override + public int getOrder() { + return HIGHEST_PRECEDENCE; + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java index b98364b1cff..818eadecabe 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java @@ -17,51 +17,55 @@ package com.alibaba.dubbo.config.spring.beans.factory.annotation; import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.spring.context.config.NamePropertyDefaultValueDubboConfigBeanCustomizer; import com.alibaba.dubbo.config.spring.context.properties.DefaultDubboConfigBinder; -import com.alibaba.dubbo.config.spring.context.properties.DubboConfigBinder; - import org.junit.Assert; import org.junit.Test; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.PropertySource; - -import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; /** * {@link DubboConfigBindingBeanPostProcessor} */ -@PropertySource({"classpath:/META-INF/config.properties"}) -@Configuration +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = { + DefaultDubboConfigBinder.class, + NamePropertyDefaultValueDubboConfigBeanCustomizer.class, + DubboConfigBindingBeanPostProcessorTest.class +}) +@TestPropertySource(properties = { + "dubbo.application.id = dubbo-demo-application", + "dubbo.application.owner = mercyblitz", + "dubbo.application.organization = Apache", + +}) public class DubboConfigBindingBeanPostProcessorTest { - @Bean("applicationBean") + @Bean("dubbo-demo-application") public ApplicationConfig applicationConfig() { return new ApplicationConfig(); } @Bean - public DubboConfigBinder dubboConfigBinder() { - return new DefaultDubboConfigBinder(); + public DubboConfigBindingBeanPostProcessor bindingBeanPostProcessor() { + return new DubboConfigBindingBeanPostProcessor("dubbo.application", "dubbo-demo-application"); } + @Autowired + private ApplicationContext applicationContext; + @Test public void test() { - final AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); - - applicationContext.register(getClass()); - - Class processorClass = DubboConfigBindingBeanPostProcessor.class; - - applicationContext.registerBeanDefinition("DubboConfigBindingBeanPostProcessor", rootBeanDefinition(processorClass).addConstructorArgValue("dubbo.application").addConstructorArgValue("applicationBean").getBeanDefinition()); - - applicationContext.refresh(); - ApplicationConfig applicationConfig = applicationContext.getBean(ApplicationConfig.class); Assert.assertEquals("dubbo-demo-application", applicationConfig.getName()); - + Assert.assertEquals("mercyblitz", applicationConfig.getOwner()); + Assert.assertEquals("Apache", applicationConfig.getOrganization()); } } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java index cb581190163..15b462e4041 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java @@ -24,12 +24,12 @@ import com.alibaba.dubbo.config.ProviderConfig; import com.alibaba.dubbo.config.RegistryConfig; import com.alibaba.dubbo.config.spring.util.ObjectUtils; - import org.junit.Assert; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.PropertySource; +import java.util.Map; import java.util.Set; import java.util.TreeSet; @@ -108,6 +108,15 @@ public void testMultiple() { ApplicationConfig applicationBean3 = context.getBean("applicationBean3", ApplicationConfig.class); Assert.assertEquals("dubbo-demo-application3", applicationBean3.getName()); + + Map protocolConfigs = context.getBeansOfType(ProtocolConfig.class); + + for (Map.Entry entry : protocolConfigs.entrySet()) { + String beanName = entry.getKey(); + ProtocolConfig protocol = entry.getValue(); + Assert.assertEquals(beanName, protocol.getName()); + } + } @EnableDubboConfig diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties index d635aa97f93..1063fe68ff1 100644 --- a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties @@ -14,9 +14,13 @@ dubbo.module.name = dubbo-demo-module dubbo.registry.address = zookeeper://192.168.99.100:32770 ## protocol +dubbo.protocol.id = dubbo dubbo.protocol.name = dubbo dubbo.protocol.port = 20880 +dubbo.protocols.rest.port=8080 +dubbo.protocols.thrift.port=9090 + ## monitor dubbo.monitor.address = zookeeper://127.0.0.1:32770