Motan 通过配置文件 启动分析
通过配置文件XML启动,入口处理也是AbstractApplicationContext类中的refresh方法,但xml是在这个调用中处理的
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
如doLoadDocument和registerBeanDefinitions。核心处理在XmlBeanDefinitionReader类的doLoadBeanDefinitions方法中,该方法也就两个函数调用,先加载XML,然后注册bean。
doLoadDocument方法,将xml加载到内存中,转换为Document对象的示例,fNodeValue存放这节点的值,如下图:(可以看到Motan的一些节点值)
nodevalue.png
doLoadBeanDefinitions方法,功能就是将xml描述的bean注册到上下文中。继续往里查看代码,一个核心处理在DefaultBeanDefinitionDocumentReader类的parseBeanDefinitions方法处:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
// 处理 spring 默认的命名空间的元素,就是xml头上spring自己的一些东西
parseDefaultElement(ele, delegate);
}
else {
// 处理自定义的元素
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
parseCustomElement方法主要处理:
- 获取命名空间uri,http://api.weibo.com/schema/motan
- 获取handlerMappings,
// handlerMappingsLocation值:META-INF/spring.handlers,spring遍历查找各个工程或包找这个文件,并获取其值
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
- 用第一步的uri从mappings中查找uri对应的值(命名空间的处理器):
com.weibo.api.motan.config.springsupport.MotanNamespaceHandler - 通过反射构建其实例,并调用其init方法
MotanNamespaceHandler的init方法注册了Motan各个自定DOM节点的解析器 - 将MotanNamespaceHandler的实例存入handlerMappings用于后续的解析
- 找到对应DOM节点的解析器,开始解析,具体看Motan的代码
后面是实例化、初始化等等各种bean的操作了,与注解的处理还不一样。
-
首先涉及Motan的方法处理是registerBeanPostProcessors(beanFactory),这里创建ServiceConfigBean的实例
- 通过invokeAwareMethods处理实现BeanFactoryAware接口的类,给ServiceConfigBean设置beanFactory。
- 通过invokeInitMethods处理实现了InitializingBean类的的afterPropertiesSet方法。ServiceConfigBean在afterPropertiesSet这里会创建注册中心bean,协议bean
-
registerListeners(),会将serviceconfigbean添加到监听列表,因为其实现了ApplicationListener接口
-
finishRefresh(); 会调用事件(实现ApplicationListener接口的类的onApplicationEvent方法),开始暴露服务
ServiceConfigBeanbean实现了下面几个接口
- BeanPostProcessor
下面是Motan源码,通过断点调试,未见调用该方法.....
// 为了让serviceBean最早加载
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
- BeanFactoryAware 设置beanFactory,用于获取bean
- InitializingBean 用于一些Motan需要的bean的创建及检测
- DisposableBean 用于容器关闭时反注册服务
- ApplicationListener<ContextRefreshedEvent> 用于在spring初始化完之后暴露服务
serviceBean 实现 InitializingBean接口,在afterPropertiesSet方法中创建必要的bean:
1、创建serviceBasicConfig的实例(getBean方法)
- 缓存的单例实例中不存在,找bean的定义
- 获取实例化策略,根据bean的定义开始创建bean的实例
- 将bean定义中的值(xml中配置的)设置到新创建的bean中
- 如果发现引用类型的值,则继续调用getBean获取(此处是要获取注册中心的实例),流程与创建serviceBasicConfig一样。
- 最后创建完返回,给ServiceConfigBean设置BasicServiceInterfaceConfig的实例
2、创建协议bean
- 解析export="demoMotan:8002",获取协议名demoMotan和端口8002
- 创建ProtocolConfig实例(getBean方法),流程与上面一致
- 创建完,通过setProtocols设置协议
3、最后再检查RegistryConfig,以防意外缺少注册中心配置(该配置在第一步中创建过)
从上面来看,要扩展spring xml语法,需要下面几个步骤
- 在resource目录下创建META-INF文件夹,并增加两个文件
(Motan的文件在motan-core工程中)
- spring.handlers,用来告诉spring自定义的命名空间处理类
- spring.schemas,用于告诉spring自定义扩展元素的定义文件的位置(xml Schema Definition)
- 实现NamespaceHandlerSupport接口,在init方法中注册各个元素的解析类
(Motan参照motan-springsupport中的MotanNamespaceHandler类) - 实现BeanDefinitionParser接口,并实现对各个元素的解析处理