dubbo啟動過程淺析

??spring 為第三方預留了集成的空間,當spring遇到非自己的命名空間時,會去META-INF/spring.handlers文件中尋找此命名空間的處理器,解析xml配置文件時,遇到此命名空間的標簽,調用對應命名空間標簽處理器,解析此標簽。那么dubbo怎么做的呢?在dubbo源碼的META-INF目錄下,我們看到有spring.handler文件,打開此文件內容為:
http://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
表明dubbo標簽的文件處理器為DubboNamespaceHandler,找到這個類我們可以發現所有標簽的解析處理邏輯。
??dubbo命名空間下所有的標簽都是調用DubboBeanDefinitionParser進行解析,此方法有兩個參數,一個是配置類,此配置類會注冊到spring IoC容器中,另一個是此bean在IoC容器中是否需要ID標識。

public BeanDefinitionparse(Element element, ParserContext parserContext) {

        return parse(element, parserContext, beanClass, required);

}

private static BeanDefinitionparse(Element element, ParserContext parserContext, Class beanClass, boolean required) {

    RootBeanDefinition beanDefinition =new RootBeanDefinition();//new一個beanDefinition

    beanDefinition.setBeanClass(beanClass);

    beanDefinition.setLazyInit(false);//立即初始化

    String id = element.getAttribute("id");

    if ((id ==null || id.length() ==0) && required) {//設置bean id

        beanDefinition.getPropertyValues().addPropertyValue("id", id);//設置bean id

    }

    if (ProtocolConfig.class.equals(beanClass)) {//此處是為服務設置協議

    }else if (ServiceBean.class.equals(beanClass)){//若class屬性不為空,ref屬性設置為class

    }else if (ProviderConfig.class.equals(beanClass)) {//遞歸解析下級標簽

    }else if (ConsumerConfig.class.equals(beanClass)) {

   }

  for (Method setter : beanClass.getMethods()) {

    String name = setter.getName();

    if (name.length() >3 && name.startsWith("set")

      && Modifier.isPublic(setter.getModifiers())

      && setter.getParameterTypes().length ==1) { //取出標簽屬性的值,設置到bean對象中

      ..........................................................................

    beanDefinition.getPropertyValues().addPropertyValue(property, reference);

    ..........................................................................

  }

    return beanDefinition;

}

DubboBeanDefinitionParser中的parse方法,首先new一個RootBeanDefinition,然后設置beanclass值,將bean的延遲初始化設為false,接著如下圖所示,如果id為空,并且id是必須的,則設置id值,具體為:
1)先從元素節點看是否能獲取到name屬性
2)如果獲取不到,且class為protocolConfig,則將id設置成dubbo,不是protocolconfig,取接口值
3)如果還是獲取不到,取class的名稱

//將剛才定義的beandefinition注冊到spring IoC容器中,并設置id值
 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);
        }

?接下來對ProtocolConfig、ServiceBean、ProviderConfig、ConsumerConfig做特殊處理。
1)ProtocolConfig:獲取IoC容器里所有的BeanDefinition,然后看這個bean是否有名稱為protocol的屬性定義,若有,且協議為當前所解析的協議,則設置此bean protocol屬性值為當前協議(此處設置為動態引用,初始化的時候才設置值,具體可參考spring bean機制)

2)ServiceBean :如果是<dubbo:service>標簽class屬性不為空,將此class設置成為一個beandefinition,并且作為屬性ref的值。(可見ref class兩個屬性二選1)

3)ProviderConfig、ConsumerConfig:逐層解析下級標簽,每個下級標簽解析成一個beanDefinition,并將provider、consumer作為下級標簽的一個屬性,值為動態引用的bean(serviceBean、ReferenceBean)

接下來就是遍歷beanClass中所有的方法(set開頭,public修飾,有參數),設置bean中屬性值

for (Method setter : beanClass.getMethods()) {

String name = setter.getName();

    if (name.length() >3 && name.startsWith("set")

&& Modifier.isPublic(setter.getModifiers())

&& setter.getParameterTypes().length ==1) {

      ..............................................................

      beanDefinition.getPropertyValues().addPropertyValue(property, reference);

    ..............................................................

}

?這樣所有配置標簽就被解析成beanDefinition交給spring管理,待所有標簽都解析完成之后,spring就會初始化Bean,由于serviceBean、ReferenceBean比較特殊,實現了一系列接口,當spring在初始化這些這兩個bean的時候,會執行相對應的方法,具體如下:

public class ServiceBeanextends ServiceConfig implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware{

    public void afterPropertiesSet()//完成發布服務所需配置的初始化

    public void onApplicationEvent(ApplicationEvent event)//完成服務的暴露

}

public class ReferenceBeanextends ReferenceConfig implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean{

    public void afterPropertiesSet()//完成引用服務所需配置的初始化

    public ObjectgetObject()throws Exception {
        return get();  //完成服務的引用
    }
}

總結:由于spring的應用廣泛,包括dubbo在內的rpc框架都利用spring IoC容器完成服務的啟動。具體如下:將發布和引用服務所需的配置定義成bean--->讀取配置文件,完成對bean的填充--->相關的bean實現接口--->spring 容器初始化bean的時候,調用相應的方法完成服務的發布和引用。
一篇好文章:https://nobodyiam.com/2017/02/26/several-ways-to-extend-spring/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。