• dubbo源码分析7——dubbo的配置解析_与spring的整合


    dubbo的配置其实就是建立在spring的命名空间的配置机制之上的。在dubbo的jar包的META-INF目录下会有spring.handlers这个文件,用来配置spring的命名空间和解析类的对应关系。打开spring.handlers文件,可知dubbo的命名空间配置的处理类为com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler,代码:

    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("monitor", new DubboBeanDefinitionParser(MonitorConfig.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 DubboBeanDefinitionParser(AnnotationBean.class, true));
        }

    DubboBeanDefinitionParser类的parse方法会处理所有的配置,具体入口就是上面这段代码。DubboBeanDefinitionParser类的parse方法的解析的目的就是把dubbo的命名空间上的配置转成相应的BeanDefinition类,以便IOC容器进行后续的实例化和注入工作。解析逻辑大致如下:

     1.  RootBeanDefinition beanDefinition = new RootBeanDefinition();    //创建BeanDefinition实例

     2.  beanDefinition.setBeanClass(beanClass);                                      //设置这个beanDefinition要实例化的类,又称beanClass, 此处的beanClass,就是上面摘录的源码中的DubboBeanDefinitionParser类的构造方法中的第一个参数

     3.  通过beanDefinition设置bean的id ,这个逻辑多一些,直接列源码,在上面注释说明

         String id = element.getAttribute("id");  //先获取元素的id属性作为bean的id 
            if ((id == null || id.length() == 0) && required) {
                String generatedBeanName = element.getAttribute("name");  //如果没有id属性,则获取元素的name属性
                if (generatedBeanName == null || generatedBeanName.length() == 0) { //如果name属性也没设,那么如果这个解析的beanClass是ProtocolConfig.class,一般对应的xml元素是 <dubbo:protocol>,那么id为dubbo,也就说明默认protocol为dubbo
                    if (ProtocolConfig.class.equals(beanClass)) {
                        generatedBeanName = "dubbo";
                    } else {                                                       //如果name属性没设,且不是ProtocolConfig.class这个情况,则获取interface属性作为id      
                        generatedBeanName = element.getAttribute("interface");
                    }
                }
                if (generatedBeanName == null || generatedBeanName.length() == 0) {//如果name属性、interface属性都没设置,且也不是ProtocolConfig.class那么就直接取beanClass的类名作为id
                    generatedBeanName = beanClass.getName();
                }
                id = generatedBeanName; 
                int counter = 2;
                while(parserContext.getRegistry().containsBeanDefinition(id)) {
                    id = generatedBeanName + (counter ++);                        //对id做防重处理
                }
            }

    至此bean的id就可以设置好了。

    4. 当前步对<dubbo:protocol/>进行进一步的处理,把当前解析的beandefinition设置到其他的已注册的beandefinition中

    if (ProtocolConfig.class.equals(beanClass)) {
                for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {
                    BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);
                    PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol");
                    if (property != null) {
                        Object value = property.getValue();
                        if (value instanceof ProtocolConfig && id.equals(((ProtocolConfig) value).getName())) {
                            definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));
                        }
                    }
                }
            }

    5.对 <dubbo:service/>的解析处理

    else if (ServiceBean.class.equals(beanClass)) {
                String className = element.getAttribute("class");  //获取<dubbo:service/>的class属性
                if(className != null && className.length() > 0) {
                    RootBeanDefinition classDefinition = new RootBeanDefinition();  //定义新的BeanDefinition为classDefinition
                    classDefinition.setBeanClass(ReflectUtils.forName(className));
                    classDefinition.setLazyInit(false);
                    parseProperties(element.getChildNodes(), classDefinition);  //解析
                    beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
                }
            } 

    上面这段代码说明:

    配置1

    <dubbo:service interface="org.huxin.dubbo.test.user.service.UserInterface"
    ref="userService" protocol="dubbo" retries="0" />

    <bean id="userService" class="org.huxin.dubbo.test.user.service.impl.UserService" />   

    可以替换成下面这种形式(但一般情况下<bean id="userService"/>都是注解驱动的)

    <dubbo:service interface="org.huxin.dubbo.test.user.service.UserInterface"
    class="org.huxin.dubbo.test.user.service.impl.UserService" protocol="dubbo"
    retries="0">
    </dubbo:service>

    6. 处理 <dubbo:provider/>下面的子元素<dubbo:service/>

    else if (ProviderConfig.class.equals(beanClass)) {
                parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);

    7.处理<dubbo:consumer/>下面的子元素<dubbo:reference/>

    else if (ConsumerConfig.class.equals(beanClass)) {
                parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefinition);
            }

    8.  对beanClass的setter和getter的属性做进一步处理 ,beanClass类如(ApplicationConfig.class、ModuleConfig.class、RegistryConfig.class、 ServiceBean.class等等)

         (1) 获取beanClass类的某个属性的setter方法

         (2) 通过StringUtils.camelToSplitName方法从setter方法中截取出property,放入到Set<String> props = new HashSet<String>();

         (3) 获取步骤(2)中的property的getter方法,如果没有,则结束对这个property的处理,回到第 (1)步取出下一个

         (4) 如果property是"parameters“、”methods“ 、”arguments“中的某一个,则会解析当前元素的子元素,看是否有这些元素需要处理,处理完成后会分别在beanDefinition中添加"parameters“、”methods“ 、”arguments“这些属性。

         (5)针对property是这几种情况的进行处理(取出property的value,实例化特定的类,放入beanDefinition中): 

                registry(单个) 、registry(多个)、 provider(多个) 、 protocol(多个),

         (6)处理其他的一些属性

    总结:

        最终,经过一番折腾,dubbo中的所有配置,就会转化为这些类的实例,类图如下:

  • 相关阅读:
    Flush the AOS cache from code
    EntityConnectionStringBuilder 构造EF连接字符串
    AX中文转拼音
    AX2012 AOT中Web部署显示二级以上菜单
    clearCompanyCache
    AX2009 打印到PDF优化
    AX ODBC读取其他SQL数据库服务器数据
    AX2009报表打印固定长度Barcode条码
    Create Product Variant
    Rename AOT Object
  • 原文地址:https://www.cnblogs.com/hzhuxin/p/7593073.html
Copyright © 2020-2023  润新知