Dubbo和Spring结合配置文件内容解析为bean的过程

标签: Dubbo-bean dubbo源码 bean加载 Spring
1416人阅读 评论(2) 收藏 举报
分类:

Dubbo 现在已经被很多公司广泛的使用,Dubbo的使用和特性本篇不做讲解,本篇讲解一下Dubbo和Spring结合配置文件内容解析为bean的过程!

Dubbo是结合Spring来进行使用的,其中bean依赖Spring的IOC容器进行管理。Spring默认的Bean加载机制肯定是不能去加载Dubbo提供的Bean,那么Dubbo中的Bean是如何加载到Spring 容器的呢?下面进行介绍:

一、从Dubbo的配置说起

搭建一个Dubbo服务框架,Dubbo的配置文件必不可少。那么首先从Dubbo的配置文件applicationProvider.xml说起,看一个Dubbo的provide配置!

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
        http://www.springframework.org/schema/beans/spring-beans.xsd  
        http://code.alibabatech.com/schema/dubbo  
        http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">   

    <!-- 提供方应用信息,用于计算依赖关系 -->
    <dubbo:application name="dubbo_provider"  />      
    <!-- 使用zookeeper注册中心暴露服务地址 -->  
    <dubbo:registry address="zookeeper://127.0.0.1:2181" />     
    <!-- 用dubbo协议在20880端口暴露服务 -->  
    <dubbo:protocol name="dubbo" port="20880" />  
    <!-- 声明需要暴露的服务接口 -->  
    <dubbo:service interface="com.dufy.service.ProviderService" ref="providerService"/>
     <!-- 具体的实现bean -->  
    <bean id="providerService" class="com.dufy.service.ProviderServiceImpl"/>
</beans> 

从配置文件内容中我们可以看出:

  1. 由于Spring提供了可扩展Schema的支持,Dubbo有自己的schema 文件!
    xmlns:dubbo=”http://code.alibabatech.com/schema/dubbo”指定Dubbo自定义Schema,xsi:schemaLocation用来指定xsd文件! XSD - < schema > 元素 -w3school
  2. Dubbo有一些自定义的标签,如
<dubbo:application
<dubbo:registry 
.....

二、Spring如何解析Dubbo的配置

1、加载Dubbo的配置文件

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(  
                new String[]{"applicationProvider.xml"}); 

Web项目,在web.xml中指定加载文件地址

<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:application_*.xml</param-value>
</context-param>

Spring容器在启动的时候,会读取到Spring默认的一些schema以及Dubbo自定义的schema,每个schema都会对应一个自己的NamespaceHandler,NamespaceHandler里面通过BeanDefinitionParser来解析配置信息并转化为需要加载的bean对象!
下面通过分析ClassPathXmlApplicationContext 加载和解析applicationProvider.xml过程!

2、Spring加载Dubbo配置文件解析过程

AbstractXmlApplicationContext的loadBeanDefinitions方法中使用XmlBeanDefinitionReader. loadBeanDefinitions加载applicationProvider.xml文件

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = this.getConfigResources();
        if(configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }

        String[] configLocations = this.getConfigLocations();
        if(configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
            //configLocations = applicationProvider.xml
        }

    }

DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法中,对加载的applicationProvider.xm文件元素使用BeanDefinitionParserDelegate对象进行解析

 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if(delegate.isDefaultNamespace(root)) {//是否是默认的NameSpace,Dubbo Namespace不是默认的
            NodeList nl = root.getChildNodes();
            for(int i = 0; i < nl.getLength(); ++i) {
                Node node = nl.item(i);
                if(node instanceof Element) {
                    Element ele = (Element)node;
                    if(delegate.isDefaultNamespace(ele)) {
                        this.parseDefaultElement(ele, delegate);
                    } else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {
        //通过代理来解析Dubbo配置文件中 Element 元素
            delegate.parseCustomElement(root);
        }

    }

进入BeanDefinitionParserDelegate 中的 parseCustomElement 方法中

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        //通过元素获取namespaceURI
        String namespaceUri = this.getNamespaceURI(ele);
        //如 ele:name 为 dubbo:application ,则namespaceUri  = http://code.alibabatech.com/schema/dubbo
        //通过NameSpaceURi 获取NamespaceHandler ,Dubbo对应的是DubboNameSpaceHandler 
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver()
        .resolve(namespaceUri);//resolve解析请往下看
        if(handler == null) {
            this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
            return null;
        } else {
            //DubboBeanDefinitionParser的parse解析
            return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
        }
    }

调用resolve()方法,处理

 public NamespaceHandler resolve(String namespaceUri) {
         //此处Map为Spring需要加载的所有namespaceUri 对应的Handler
         //即 Map<namespaceUri ,handlerOrClassName >
        Map handlerMappings = this.getHandlerMappings();
        //这里因为namespaceUri 为Dubbo命名空间,故 Handler 为 DubboNamespaceHandler 
        Object handlerOrClassName = handlerMappings.get(namespaceUri);
        .....
        namespaceHandler.init();//调用init方法进行初始操作
        handlerMappings.put(namespaceUri, namespaceHandler);
        return namespaceHandler;
       .....

        }
    }

遇到dubbo名称空间 ,首先会调用DubboNamespaceHandler init 进行初始化操作,代码如下

public class DubboNamespaceHandler extends NamespaceHandlerSupport {
    public DubboNamespaceHandler() {
    }

    public void init() {
        this.registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        this.registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        this.registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        this.registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        this.registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        this.registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        this.registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        this.registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        this.registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        this.registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
    }
}

根据不同的XML节点,会委托NamespaceHandlerSupport找出合适的BeanDefinitionParser,其中Dubbo所有的标签都使用 DubboBeanDefinitionParser进行解析,基于一对一属性映射,将XML标签解析为Bean对象。

三:DubboBeanDefinitionParser解析过程简单介绍

由于DubboBeanDefinitionParser中 parse转换的过程代码还是比较复杂,只抽离出来bean的注册这一块的代码:

private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {

        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClass(beanClass);
        beanDefinition.setLazyInit(false);
        String id = element.getAttribute("id");
        //省略......
         if(id != null && id.length() > 0) {
            if(parserContext.getRegistry().containsBeanDefinition(id)) {
                throw new IllegalStateException("Duplicate spring bean id " + id);
            }
            //registerBeanDefinition 注册Bean的定义
            //具体的id如下 applicationProvider.xml解析后的显示 id,
            //如id="dubbo_provider"  beanDefinition = "ApplicationConfig"
            parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
            beanDefinition.getPropertyValues().addPropertyValue("id", id);
        }

     //省略.....

上面的applicationProvider.xml转换后大概是下面这个样子:

<!-- 提供方应用信息,用于计算依赖关系 -->
<bean id="dubbo_provider" class="com.alibaba.dubbo.config.ApplicationConfig"/>
<!-- 使用zookeeper注册中心暴露服务地址 -->
<bean id="registryConfig" class="com.alibaba.dubbo.config.RegistryConfig">
    <property name="address" value="127.0.0.1:2181"/>
    <property name="protocol" value="zookeeper"/>
</bean>
  <!-- 用dubbo协议在20880端口暴露服务 -->  
<bean id="dubbo" class="com.alibaba.dubbo.config.ProtocolConfig">
    <property name="port" value="20880"/>
</bean>
<!-- 声明需要暴露的服务接口 -->  
<bean id="com.dufy.service.ProviderService" class="com.alibaba.dubbo.config.spring.ServiceBean">
    <property name="interface" value="com.dufy.service.ProviderService"/>
    <property name="ref" ref="providerService"/>
</bean>
<bean id="providerService" class="com.dufy.service.ProviderServiceImpl" />

通过DubboBeanDefinitionParser的 parse会将class信息封装成BeanDefinition,然后将BeanDefinition再放进DefaultListableBeanFactory的beanDefinitionMap中。
最后通过Spring bean 的加载机制进行加载!


欢迎访问我的csdn博客,愿我们一同成长!

不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!

博客首页http://blog.csdn.net/u010648555

查看评论

[转载,感觉写的非常详细]DUBBO配置方式详解

DUBBO 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,是阿里巴巴 SOA 服务化治理方案的核心框架,每天为 2,000+ 个服务提供 3,000,000,000+ 次...
  • huangjin0507
  • huangjin0507
  • 2016-08-17 20:10:13
  • 30549

精通Dubbo——Dubbo配置文件详解

依赖的jar理论上Dubbo可以只依赖JDK,不依赖于任何三方库运行,只需配置使用JDK相关实现策略。缺省依赖(系统默认)通过mvn dependency:tree > dep.log命令(Eclip...
  • fuyuwei2015
  • fuyuwei2015
  • 2017-06-01 22:44:35
  • 6252

dubbo 配置文件详解

一、dubbo常用配置 dubbo:service/> 服务配置,用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心。 eg、dubbo:ser...
  • z69183787
  • z69183787
  • 2017-12-19 18:17:57
  • 230

集成Dubbo服务(Spring)

Dubbo是什么? Dubbo是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。 Dubbo[]...
  • qduningning
  • qduningning
  • 2014-11-24 18:05:11
  • 110771

解决spring的dubbo配置文件报错解决思路

在导入maven工程的时候,报出如下错误:      cvc-complex-type.2.4.c: The matching wildcard is strict, but no declarati...
  • u012263493
  • u012263493
  • 2015-08-29 16:15:30
  • 1089

dubbo+Spring+SpringMVC实例,spring配置文件启动

  • 2014年12月10日 16:02
  • 15KB
  • 下载

Dubbo和Spring集成Demo

Zookeeper安装和启动 http://mirrors.hust.edu.cn/apache/zookeeper/下载,我的版本是 3.4.5。 解压到 D:\zookeeper-3.4.5 配置...
  • lfsf802
  • lfsf802
  • 2015-04-30 20:48:29
  • 35773

学习了一下XML,并结合相应的知识讲解了一下spring的dubbo配置

定义xml中所有子元素的默认命名空间,只要不给node加前缀就默认加上这个命名空间 ...
  • u010793761
  • u010793761
  • 2016-08-24 15:36:15
  • 1564

【Dubbo实战】 Dubbo+Zookeeper+Spring整合应用篇-Dubbo基于Zookeeper实现分布式服务(二)

Dubbo与Zookeeper、Spring整合使用 Dubbo采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可,Dubbo基于Spri...
  • hejingyuan6
  • hejingyuan6
  • 2015-08-10 21:31:29
  • 111007

Dubbo——配置Dubbo的两种方法

配置Dubbo的两种方法 1、基于XML配置Dubbo框架的原理 Dubbo基于spring可扩展Schema为Business层提供了可配置化的支持。具体的设计步骤如下: 一、设计配置属性...
  • meilong_whpu
  • meilong_whpu
  • 2017-05-15 16:04:52
  • 739
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 57万+
    积分: 6812
    排名: 4298
    联系方式
    其实我想要  一种美梦睡不着  一种心脏的狂跳  瓦解界线不被撂倒 奔跑 依靠  我心中最想要  看你看过的浪潮  陪你放肆地年少  从你眼神能找到 解药 -林俊杰【伟大的渺小】

    QQ:742981086

    java编程艺术 600756207 共同学习!

    ------------

    GitHub

    个人博客

    博客专栏
    最新评论