通過配置文件XML啟動,入口處理也是AbstractApplicationContext類中的refresh方法,但xml是在這個調(diào)用中處理的
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();如doLoadDocument和registerBeanDefinitions。核心處理在XmlBeanDefinitionReader類的doLoadBeanDefinitions方法中,該方法也就兩個函數(shù)調(diào)用,先加載XML,然后注冊bean。
doLoadDocument方法,將xml加載到內(nèi)存中,轉(zhuǎn)換為Document對象的示例,fNodeValue存放這節(jié)點的值,如下圖:(可以看到Motan的一些節(jié)點值)

doLoadBeanDefinitions方法,功能就是將xml描述的bean注冊到上下文中。繼續(xù)往里查看代碼,一個核心處理在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 默認(rèn)的命名空間的元素,就是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對應(yīng)的值(命名空間的處理器):
com.weibo.api.motan.config.springsupport.MotanNamespaceHandler - 通過反射構(gòu)建其實例,并調(diào)用其init方法
MotanNamespaceHandler的init方法注冊了Motan各個自定DOM節(jié)點的解析器 - 將MotanNamespaceHandler的實例存入handlerMappings用于后續(xù)的解析
- 找到對應(yīng)DOM節(jié)點的解析器,開始解析,具體看Motan的代碼
后面是實例化、初始化等等各種bean的操作了,與注解的處理還不一樣。
-
首先涉及Motan的方法處理是registerBeanPostProcessors(beanFactory),這里創(chuàng)建ServiceConfigBean的實例
- 通過invokeAwareMethods處理實現(xiàn)BeanFactoryAware接口的類,給ServiceConfigBean設(shè)置beanFactory。
- 通過invokeInitMethods處理實現(xiàn)了InitializingBean類的的afterPropertiesSet方法。ServiceConfigBean在afterPropertiesSet這里會創(chuàng)建注冊中心bean,協(xié)議bean
registerListeners(),會將serviceconfigbean添加到監(jiān)聽列表,因為其實現(xiàn)了ApplicationListener接口
finishRefresh(); 會調(diào)用事件(實現(xiàn)ApplicationListener接口的類的onApplicationEvent方法),開始暴露服務(wù)
ServiceConfigBeanbean實現(xiàn)了下面幾個接口
- BeanPostProcessor
下面是Motan源碼,通過斷點調(diào)試,未見調(diào)用該方法.....
// 為了讓serviceBean最早加載
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
- BeanFactoryAware 設(shè)置beanFactory,用于獲取bean
- InitializingBean 用于一些Motan需要的bean的創(chuàng)建及檢測
- DisposableBean 用于容器關(guān)閉時反注冊服務(wù)
- ApplicationListener<ContextRefreshedEvent> 用于在spring初始化完之后暴露服務(wù)
serviceBean 實現(xiàn) InitializingBean接口,在afterPropertiesSet方法中創(chuàng)建必要的bean:
1、創(chuàng)建serviceBasicConfig的實例(getBean方法)
- 緩存的單例實例中不存在,找bean的定義
- 獲取實例化策略,根據(jù)bean的定義開始創(chuàng)建bean的實例
- 將bean定義中的值(xml中配置的)設(shè)置到新創(chuàng)建的bean中
- 如果發(fā)現(xiàn)引用類型的值,則繼續(xù)調(diào)用getBean獲?。ù颂幨且@取注冊中心的實例),流程與創(chuàng)建serviceBasicConfig一樣。
- 最后創(chuàng)建完返回,給ServiceConfigBean設(shè)置BasicServiceInterfaceConfig的實例
2、創(chuàng)建協(xié)議bean
- 解析export="demoMotan:8002",獲取協(xié)議名demoMotan和端口8002
- 創(chuàng)建ProtocolConfig實例(getBean方法),流程與上面一致
- 創(chuàng)建完,通過setProtocols設(shè)置協(xié)議
3、最后再檢查RegistryConfig,以防意外缺少注冊中心配置(該配置在第一步中創(chuàng)建過)
從上面來看,要擴(kuò)展spring xml語法,需要下面幾個步驟
- 在resource目錄下創(chuàng)建META-INF文件夾,并增加兩個文件
(Motan的文件在motan-core工程中)
- spring.handlers,用來告訴spring自定義的命名空間處理類
- spring.schemas,用于告訴spring自定義擴(kuò)展元素的定義文件的位置(xml Schema Definition)
- 實現(xiàn)NamespaceHandlerSupport接口,在init方法中注冊各個元素的解析類
(Motan參照motan-springsupport中的MotanNamespaceHandler類) - 實現(xiàn)BeanDefinitionParser接口,并實現(xiàn)對各個元素的解析處理