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中的所有配置,就会转化为这些类的实例,类图如下:

dubbo源码分析7——dubbo的配置解析_与spring的整合的更多相关文章

  1. Dubbo源码分析:Dubbo协议解码

    Dubbo协议解码时序图

  2. Dubbo源码分析

    Dubbo源码分析1 Dubbo源码分析2 dubbo源码阅读:rpc请求处理流程(1) 架构设计:系统间通信(17)——服务治理与Dubbo 中篇(分析) 13. Dubbo原理解析-注册中心之Zo ...

  3. dubbo源码分析6-telnet方式的管理实现

    dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...

  4. dubbo源码分析2-reference bean发起服务方法调用

    dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...

  5. dubbo源码分析3-service bean的创建与发布

    dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...

  6. dubbo源码分析一:整体分析

    本文作为dubbo源码分析的第一章,先从总体上来分析一下dubbo的代码架构.功能及优缺点,注意,本文只分析说明开源版本提供的代码及功能. 1.dubbo的代码架构:  spring适配层:常规的sp ...

  7. Dubbo 源码分析 - 服务调用过程

    注: 本系列文章已捐赠给 Dubbo 社区,你也可以在 Dubbo 官方文档中阅读本系列文章. 1. 简介 在前面的文章中,我们分析了 Dubbo SPI.服务导出与引入.以及集群容错方面的代码.经过 ...

  8. Dubbo 源码分析 - 集群容错之 LoadBalance

    1.简介 LoadBalance 中文意思为负载均衡,它的职责是将网络请求,或者其他形式的负载"均摊"到不同的机器上.避免集群中部分服务器压力过大,而另一些服务器比较空闲的情况.通 ...

  9. Dubbo 源码分析 - 集群容错之 Cluster

    1.简介 为了避免单点故障,现在的应用至少会部署在两台服务器上.对于一些负载比较高的服务,会部署更多台服务器.这样,同一环境下的服务提供者数量会大于1.对于服务消费者来说,同一环境下出现了多个服务提供 ...

随机推荐

  1. 如何修改Tomcat的默认项目发布路径

    tomcat默认的项目发布目录是/webapp/ROOT,如果想自定义发布目录,应该怎么办呢? 修改配置文件 首先,修改$tomcat/conf/server.xml文件. 在server.xml文件 ...

  2. centos 7.2 部署并升级gitlab

    事由: 老git服务器centos 7.2上的git版本是8.13.5,先特在一台测试机centos 7.2上安装git 8.13.5 后,还原git后,在对测试服务器上git进行升级操作. 测试服务 ...

  3. spring XML配置参数替代properties文件

    xml中配置BEAN与参数 <bean id="beanXXX" class="com.benXXXX" init-method="initia ...

  4. 4、JPA-EntityManager.merge()

    EntityManager#merge merge() 用于处理 Entity 的同步.即数据库的插入和更新操作 merge的几种情况 1. 若传入的是一个临时对象 package jpa.test; ...

  5. 12.代理模式(Proxy Pattern)

    直接与间接:   人们对复杂的软件系统常有一种处理手法,即增加一层间接层,从而对系统获得一种更为灵活.满足特定需求的解决方案.                                      ...

  6. jmeter(高并发测试)

    1.首先jmeter需要JDK8以上得运行环境 2.下载jmeter,官方网址:http://jmeter.apache.org/download_jmeter.cgi 3.安装jmeter.jmet ...

  7. 全面理解JavaScript中的 this

    全面理解JavaScript中的 this 上下文 VS 作用域 作用域(scope) 是在运行时代码中的某些特定部分中变量,函数和对象的可访问性.换句话 说,作用域决定了代码区块中变量和其他资源的可 ...

  8. c++中sizeof的理解

    1. 例题 #include <iostream> class A {}; class B { char m_data; }; class C { ]; }; class D { char ...

  9. JAVA正确地自定义比较对象---如何重写equals方法和hashCode方法

    在实际应用中经常会比较两个对象是否相等,比如下面的Address类,它有两个属性:String province 和 String city. public class Address { priva ...

  10. [Windows] [VS] [C] [取得指针所指内存的十六进制形式字符串]

    接口定义如下: #include <Windows.h> // 取得指针所指内存的十六进制形式字符串,size指定字节长度 #define Mem_toString(address, si ...