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/

最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352