dubbo——spring初始化


研究dubbo就先從自己最感興趣的開始吧

一、構建dubbo源碼環境

① dubbo源碼在github中,右上角fork一個分支到自己的github,然后直接git clone拉代碼到本地。(用手機熱點拉代碼有驚喜)

② 改阿里雲鏡像,maven的settings.xml

  <localRepository>D:/mavenRepository</localRepository>
  <mirrors>
     <mirror>
        <id>nexus-aliyun</id>
        <mirrorOf>*</mirrorOf>
        <name>Nexus aliyun</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public</url>
    </mirror> 
  </mirrors>

③ 導入maven項目到idea中,等待jar依賴下載。

前期學習目標:主要是過一遍源碼流程,網上看的架構圖都太抽象了,看完源碼之后,再去理解。

二、配置解析

官方已經推薦注解形式配置dubbo的服務了,由於工作時用的都是xml配置文件配置dubbo的服務,直接從源碼查找注解解析對於我來說有點無從下手的感覺。還是從xml配置文件入手順手一點。dubbo-demo>dubbo-demo-xml>dubbo-demo-xml-provider下的一個提供xml配置例子。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <dubbo:application metadata-type="remote" name="demo-provider"/>
    <dubbo:metadata-report address="zookeeper://127.0.0.1:2181"/>

    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>

    <dubbo:protocol name="dubbo"/>

    <bean id="demoService" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/>

    <dubbo:service interface="org.apache.dubbo.demo.DemoService" ref="demoService"/>

</beans>

通過spring.handlers文件找到dubbo命名空間的解析類

/* dubbo-config/dubbo-config-spring/src/main/resources/META-INF/spring.handlers */
http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
http\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler

Apache和阿里巴巴版本的命名空間進行了統一,指向的是一個命名空間解析類

/* org.apache.dubbo.config.spring.schema.DubboNamespaceHandler#init */
    public void init() {
        registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("config-center", new DubboBeanDefinitionParser(ConfigCenterBean.class, true));
        registerBeanDefinitionParser("metadata-report", new DubboBeanDefinitionParser(MetadataReportConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("metrics", new DubboBeanDefinitionParser(MetricsConfig.class, true));
        registerBeanDefinitionParser("ssl", new DubboBeanDefinitionParser(SslConfig.class, true));
        registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
    }

前面spring——scan()中是根據注解解析成BeanDefinition,還沒有研究過xml解析過程,這里走一遍吧,看看什么時候會調用上面init方法

/* AbstractApplicationContex.refresh()-->
AbstractApplicationContext.obtainFreshBeanFactory()-->
AbstractRefreshableApplicationContext.refreshBeanFactory()-->
AbstractXmlApplicationContext.loadBeanDefinitions()-->
AbstractXmlApplicationContext.loadBeanDefinitions()(重載方法)-->
AbstractBeanDefinitionReader.loadBeanDefinitions()-->
XmlBeanDefinitionReader.loadBeanDefinitions()-->
XmlBeanDefinitionReader.loadBeanDefinitions()(重載方法)-->
XmlBeanDefinitionReader.doLoadBeanDefinitions()-->
XmlBeanDefinitionReader.registerBeanDefinitions()-->
DefaultBeanDefinitionDocumentReader.registerBeanDefinitions()-->
DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions()-->
DefaultBeanDefinitionDocumentReader.parseBeanDefinitions()-->
BeanDefinitionParserDelegate.parseCustomElement()-->
BeanDefinitionParserDelegate.parseCustomElement()(重載方法)*/

    public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        //解析根節點時,獲取xml根節點的xmlns屬性,然后緩存起來
        //dubbo的是http://dubbo.apache.org/schema/dubbo
        String namespaceUri = getNamespaceURI(ele);
        //初始化NamespaceHandler
        //① 獲取META-INF/spring.handlers文件得到指定NamespaceHandler的className
        //   dubbo是org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
        //② 反射初始化並調用NamespaceHandler.init()注冊所有的節點解析器
        //③ 返回namespaceHandler
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler == null) {
            error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
            return null;
        }
        //namespaceHandle根據子節點名找到解析類,解析標簽生成BeanDefinition
 return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));     }

DubboNamespaceHandler.parse():標簽節點解析

/* org.apache.dubbo.config.spring.schema.DubboNamespaceHandler#parse */
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        //獲取BeanFactory
        BeanDefinitionRegistry registry = parserContext.getRegistry();
        //注解注解相關的解析器
        registerAnnotationConfigProcessors(registry);
        //注冊兩個監聽器
        //DubboLifecycleComponentApplicationListener
        //DubboBootstrapApplicationListener(處理服務注冊邏輯,IOC初始化refresh的最后一步finishrefresh())
        registerApplicationListeners(registry);
        //標簽節點解析為BeanDefinition
        BeanDefinition beanDefinition = super.parse(element, parserContext);
        setSource(beanDefinition);
        return beanDefinition;
    }

總結:springIOC初始化主要完成兩個任務

1、提前初始化注解解析器,注冊兩個監聽器,一個用於生命周期監聽,一個用於serviceBean注冊到注冊表

2、將標簽解析成bean,並生成實例

3、注冊到注冊表(DubboBootstrapApplicationListener.onApplicationEvent())

  

補充:

1、上面所有Config都繼承了AbstractConfig,需要注意的是AbstractConfig的一個方法被@PostConstruct注解。

@PostConstruct注解:Bean初始化(DI)后,BeanPostProcessor處理器會以反射的方式,使bean實例執行此方法。

這里addIntoConfigManager()方法作用:將上面所有的config信息,都放入configManager中。

    @PostConstruct
    public void addIntoConfigManager() {
        ApplicationModel.getConfigManager().addConfig(this);
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM