您的位置:首页 > 编程语言 > Java开发

dubbo 源码学习笔记 (四) —— 配置模块

2017-10-14 16:55 507 查看
欢迎访问我的个人博客休息的风

对于dubbo的配置,采用的是spring的一个解析配置文件的机制。与spring是连接的,也是解析成BeanDefinition,让spring管理生成对象放入spring容器中。(具体从spring加载xml转换为beanDefinition的过程可以去看我的另一篇博客spring
源码学习笔记(一)—— spring ioc 之加载XML转换为BeanDefinition)dubbo对于配置的xml的解析在DubboNamespaceHandler这个类里定义,具体的解析过程在DubboBeanDefinitionParser这个类里执行。DubboBeanDefinitionParser.parse这个方法里,会对所有的配置文件的属性进行解析,将解析的结果存放到BeanDefinition对象中。由于这个parse方法对所有的配置,如<dubbo:application 
/>、<dubbo:service />等都在parse方法里面解析,没有一 一区分。所以这个方法有将近200行的代码。所有的配置文件都与ApplicationConfig、ServiceConfig等数据结构对应。也就是说,这个转换过程为XML文件->BeanDefinition->XXXConfig对象。

具体的解析过程如下:

private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(beanClass);
beanDefinition.setLazyInit(false);
//解析id的过程
String id = element.getAttribute("id");
if ((id == null || id.length() == 0) && required) {
String generatedBeanName = element.getAttribute("name");
if (generatedBeanName == null || generatedBeanName.length() == 0) {
if (ProtocolConfig.class.equals(beanClass)) {
generatedBeanName = "dubbo";
} else {
generatedBeanName = element.getAttribute("interface");
}
}
//省略代码。。。
}
if (id != null && id.length() > 0) {
if (parserContext.getRegistry().containsBeanDefinition(id)) {
throw new IllegalStateException("Duplicate spring bean id " + id);
}
parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
beanDefinition.getPropertyValues().addPropertyValue("id", id);
}
//对<dubbo:protocol>的处理
if (ProtocolConfig.class.equals(beanClass)) {
for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {
BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);
PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol");
if (property != null) {
Object value = property.getValue();
if (value instanceof ProtocolConfig && id.equals(((ProtocolConfig) value).getName())) {
definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));
}
}
}
//对<dubbo:service>的处理
} else if (ServiceBean.class.equals(beanClass)) {
String className = element.getAttribute("class");
if (className != null && className.length() > 0) {
RootBeanDefinition classDefinition = new RootBeanDefinition();
classDefinition.setBeanClass(ReflectUtils.forName(className));
classDefinition.setLazyInit(false);
parseProperties(element.getChildNodes(), classDefinition);
beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
}
//对<dubbo:provider>的处理
} else if (ProviderConfig.class.equals(beanClass)) {
parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);
} else if (ConsumerConfig.class.equals(beanClass)) {//对<dubbo:consumer>的处理
parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefinition);
}
Set<String> props = new HashSet<String>();
ManagedMap parameters = null;
//对set值的解析过程
for (Method setter : beanClass.getMethods()) {
String name = setter.getName();
if (name.length() > 3 && name.startsWith("set")
&& Modifier
1060e
.isPublic(setter.getModifiers())
&& setter.getParameterTypes().length == 1) {
//省略一大段代码
//对每个属性值的解析过程

}
}
//解析parameters的过程
NamedNodeMap attributes = element.getAttributes();
int len = attributes.getLength();
for (int i = 0; i < len; i++) {
//省略代码。。。
}
if (parameters != null) {
beanDefinition.getPropertyValues().addPropertyValue("parameters", parameters);
}
return beanDefinition;
}

也不难理解,就是分别对xml里面的配置信息转换到BeanDefinition里面一对一对的属性。每个配置文件分别对每个配置的属性值进行解析,最后都形成一个BeanDefinition。之后再由spring去生成对应的XXXConfig对象,放到spring容器中。

再来看下整个XXXConfig的一个类图情况。(图片有点小,请点击新的页签进行查看)



核心类就是最底层的ServiceBean、ReferenceBean、AnnotationBean这三个类。接下来我们分别做个介绍。

ServiceBean实现了ApplicationContextAware、BeanNameAware接口,在springioc的过程中,会对applicationContext、beanName调用相应的set方法进行依赖注入赋值。实现InitializingBean、DisposableBean,就是在spring容器初始化对象和销毁对象时,做一些自定义的操作。

@SuppressWarnings({"unchecked", "deprecation"})
public void afterPropertiesSet() throws Exception {
//设置配置属性的值
//省略代码。。。
if (!isDelay()) {
//dubbo服务暴露的入口
export();
}
}


而实现了ApplicationListener,则是接当前类做为一个事件监听器,在spring发布一个事件时,能做相应的处理。在setApplicationContext里有把这个监听器注册到spring中的操作。

public void onApplicationEvent(ApplicationEvent event) {
if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) {
if (isDelay() && !isExported() && !isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + getInterface());
}
//dubbo服务暴露的入口
export();
}
}
}


public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
SpringExtensionFactory.addApplicationContext(applicationContext);
if (applicationContext != null) {
SPRING_CONTEXT = applicationContext;
try {
//在这里注册监听到applicationContext中
Method method = applicationContext.getClass().getMethod("addApplicationListener", new Class<?>[]{ApplicationListener.class}); // 兼容Spring2.0.1
method.invoke(applicationContext, new Object[]{this});
supportedApplicationListener = true;
} catch (Throwable t) {
if (applicationContext instanceof AbstractApplicationContext) {
try {
//在这里注册监听到applicationContext中
Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", new Class<?>[]{ApplicationListener.class}); // 兼容Spring2.0.1
if (!method.isAccessible()) {
method.setAccessible(true);
}
method.invoke(applicationContext, new Object[]{this});
supportedApplicationListener = true;
} catch (Throwable t2) {
}
}
}
}
}


这样,ServiceBean就具体自定义初始化、销毁、设置applicationContext、beanName值和ApplicationListener事件监听的功能。

ReferenceBean实现了ApplicationContextAware, InitializingBean, DisposableBean这三个接口,也就是有设置applicationContext值、自定义初始化、销毁的功能。

public void afterPropertiesSet() throws Exception {
//省略很多代码
//相关属性值的设置
Boolean b = isInit();
if (b == null && getConsumer() != null) {
b = getConsumer().isInit();
}
if (b != null && b.booleanValue()) {
//dubbo引用服务的入口
getObject();
}
}


其中,实现FactoryBean,因为实例化该bean过程比较复杂,通过实现该接口定制实例化bean的逻辑。也就是,这里的getObject方法,是dubbo方法引用的入口。

public Object getObject() throws Exception {
//dubbo引用服务的入口,调用ReferenceConfig的get()方法
return get();
}


AnnotationBean实现了DisposableBean接口,在销毁对象时,对服务进行反暴露,对引用进行销毁;实现了ApplicationContextAware,能设置applicationContext的值;实现了BeanFactoryPostProcessor接口,可以修改bean的配置信息;

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
if (annotationPackage == null || annotationPackage.length() == 0) {
return;
}
if (beanFactory instanceof BeanDefinitionRegistry) {
try {
// init scanner
Class<?> scannerClass = ReflectUtils.forName("org.springframework.context.annotation.ClassPathBeanDefinitionScanner");
Object scanner = scannerClass.getConstructor(new Class<?>[]{BeanDefinitionRegistry.class, boolean.class}).newInstance(new Object[]{(BeanDefinitionRegistry) beanFactory, true});
// add filter
Class<?> filterClass = ReflectUtils.forName("org.springframework.core.type.filter.AnnotationTypeFilter");
Object filter = filterClass.getConstructor(Class.class).newInstance(Service.class);
Method addIncludeFilter = scannerClass.getMethod("addIncludeFilter", ReflectUtils.forName("org.springframework.core.type.filter.TypeFilter"));
addIncludeFilter.invoke(scanner, filter);
// scan packages
String[] packages = Constants.COMMA_SPLIT_PATTERN.split(annotationPackage);
Method scan = scannerClass.getMethod("scan", new Class<?>[]{String[].class});
scan.invoke(scanner, new Object[]{packages});
} catch (Throwable e) {
// spring 2.0
}
}
}


而实现了BeanPostProcessor接口,能在初始化bean时增加前后置操作。前置操作引用dubbo的服务,后置操作暴露dubbo服务

public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (!isMatchPackage(bean)) {
return bean;
}
//省略代码。。。
Reference reference = method.getAnnotation(Reference.class);
if (reference != null) {
//dubbo引用服务入口,处理在set方法上面@Reference的注解
Object value = refer(reference, method.getParameterTypes()[0]);
if (value != null) {
method.invoke(bean, new Object[]{value});
}
}
} //省略代码。。。
}
}
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
Reference reference = field.getAnnotation(Reference.class);
if (reference != null) {
//dubbo引用服务入口,处理类成员变量上的@Reference注解
Object value = refer(reference, field.getType());
if (value != null) {
field.set(bean, value);
}
}
} //省略代码。。。
return bean;
}


public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (!isMatchPackage(bean)) {
return bean;
}
Service service = bean.getClass().getAnnotation(Service.class);
//省略代码。。。。
//相关配置信息的处理
serviceConfigs.add(serviceConfig);
//暴露dubbo服务入口
serviceConfig.export();
}
return bean;
}


这三个bean由spring容器接管,也是dubbo与spring结合的交接处。在ServiceBean初始化(afterPropertiesSet)会调用export方法进行dubbo服务暴露;在ReferenceBean.getObject时,会调用init方法进行dubbo服务引用。AnnotationBean与注解配置相对应,在初始化的前后置操作,前置引用dubbo服务,后置暴露dubbo服务。销毁时进行引用销毁,服务反暴露。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息