美文网首页
dubbo启动过程浅析

dubbo启动过程浅析

作者: mikewt | 来源:发表于2017-12-30 16:44 被阅读0次

      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/

    相关文章

      网友评论

          本文标题:dubbo启动过程浅析

          本文链接:https://www.haomeiwen.com/subject/ivfngxtx.html