Motan 通過配置文件 啟動分析

通過配置文件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é)點值)


nodevalue.png

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方法主要處理:

// 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)對各個元素的解析處理
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容