Skip to content

Commit

Permalink
Polish apache#3189 Simplify externalized configuration of Dubbo Proto…
Browse files Browse the repository at this point in the history
…col name
  • Loading branch information
mercyblitz committed Jan 18, 2019
1 parent 688bef3 commit 85b0b54
Show file tree
Hide file tree
Showing 7 changed files with 221 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,26 @@
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;
import org.springframework.beans.factory.InitializingBean;
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}
*
Expand Down Expand Up @@ -62,6 +70,8 @@ public class DubboConfigBindingBeanPostProcessor implements BeanPostProcessor, A

private boolean ignoreInvalidFields = true;

private List<DubboConfigBeanCustomizer> configBeanCustomizers = Collections.emptyList();

/**
* @param prefix the prefix of Configuration Properties
* @param beanName the binding Bean Name
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
Expand All @@ -146,6 +180,16 @@ public void afterPropertiesSet() throws Exception {

}

private void initConfigBeanCustomizers() {

Collection<DubboConfigBeanCustomizer> configBeanCustomizers =
beansOfTypeIncludingAncestors(applicationContext, DubboConfigBeanCustomizer.class).values();

this.configBeanCustomizers = new ArrayList<DubboConfigBeanCustomizer>(configBeanCustomizers);

AnnotationAwareOrderComparator.sort(this.configBeanCustomizers);
}

/**
* Create {@link DubboConfigBinder} instance.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -107,6 +108,8 @@ private void registerDubboConfigBeans(String prefix,

}

registerDubboConfigBeanCustomizers(registry);

}

private void registerDubboConfigBean(String beanName, Class<? extends AbstractConfig> configClass,
Expand Down Expand Up @@ -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) {

Expand Down
Original file line number Diff line number Diff line change
@@ -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}.
* <p>
* 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);
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -108,6 +108,15 @@ public void testMultiple() {
ApplicationConfig applicationBean3 = context.getBean("applicationBean3", ApplicationConfig.class);
Assert.assertEquals("dubbo-demo-application3", applicationBean3.getName());


Map<String, ProtocolConfig> protocolConfigs = context.getBeansOfType(ProtocolConfig.class);

for (Map.Entry<String, ProtocolConfig> entry : protocolConfigs.entrySet()) {
String beanName = entry.getKey();
ProtocolConfig protocol = entry.getValue();
Assert.assertEquals(beanName, protocol.getName());
}

}

@EnableDubboConfig
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

0 comments on commit 85b0b54

Please sign in to comment.