Dubbo配置文件解析

1,配置信息

先看看dubbo官方文档给出的初始化过程:

基于 dubbo.jar 内的 META-INF/spring.handlers 配置,Spring 在遇到 dubbo 名称空间时,会回调 DubboNamespaceHandler。
所有 dubbo 的标签,都统一用 DubboBeanDefinitionParser 进行解析,基于一对一属性映射,将 XML 标签解析为 Bean 对象。

找到dubbo.jar中的spring.handlers及DubboBeanDefinitionParser:

spring.handlers:

http\://dubbo.apache.org/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler

DubboBeanDefinitionParser:

public class DubboNamespaceHandler extends NamespaceHandlerSupport {

    static {
        Version.checkDuplicate(DubboNamespaceHandler.class);
    }

    @Override
    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 AnnotationBeanDefinitionParser());
    }
}

上述registerBeanDefinitionParser注册对应标签的解释器,即当遇到"application"(即<dubbo:application/>)时,使用
new DubboBeanDefinitionParser(ApplicationConfig.class, true)对其进行解析。

dubbo配置文件及其意义:

 1、xmlns="http://www.springframework.org/schema/beans"
声明xml文件默认的命名空间,表示未使用其他命名空间的所有标签的默认命名空间。  

2、xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
声明XML Schema 实例,声明后就可以使用 schemaLocation 属性  

3、xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
声明前缀为dubbo的命名空间,其惟一的作用是赋予命名空间一个惟一的名称。当命名空间被定义在元素的开始标签中时,所有带有相同前缀的子元素都会与同一个命名空间相关联。即当spring解析以dubbo开头的标签时,会把其命名空间设置为"http://code.alibabatech.com/schema/dubbo",而这个命名空间名称和spring.handlers中的一个key是相同的,这即是它们产生联系的地方。

4、xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd
        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"
这个从命名可以看出个大概,指定Schema的位置这个属性必须结合命名空间使用。这个属性有两个值,第一个
值表示需要使用的命名空间。第二个值表示供命名空间使用的 XML schema 的位置。  

2,源码解析

配置文件解析发生在容器refresh的obtainFreshBeanFactory阶段

调用栈:

进到XmlBeanDefinitionReader#doLoadBeanDefinitions中:

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            //将配置文件解析为Document对象,其中级联包含子节点,每个子节点代表一个配置项
            Document doc = doLoadDocument(inputSource, resource);
            return registerBeanDefinitions(doc, resource);
        }
         ..........
    }

继续往下走,来到DefaultBeanDefinitionDocumentReader#parseBeanDefinitions,这里开始遍历解析子节点:

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    if (delegate.isDefaultNamespace(root)) {
        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)) {
                    parseDefaultElement(ele, delegate);
                }
                else {
                    delegate.parseCustomElement(ele);
                }
            }
        }
    }
    else {
        delegate.parseCustomElement(root);
    }
}

由于是自定义的配置,将会进入delegate.parseCustomElement(ele);

public BeanDefinition parseCustomElement(Element ele) {
    return parseCustomElement(ele, null);
}

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    //获取命名空间,如果是dubbo的配置,将会是"http://code.alibabatech.com/schema/dubbo"
    String namespaceUri = getNamespaceURI(ele);
    //更具命名空间,查找对应的Handler
    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    if (handler == null) {
        error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
        return null;
    }
    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

进到DefaultNamespaceHandlerResolver#resolve:

public NamespaceHandler resolve(String namespaceUri) {
    //从jar包的META-INF/spring.handlers中读取Handler信息
    Map<String, Object> handlerMappings = getHandlerMappings();
    Object handlerOrClassName = handlerMappings.get(namespaceUri);
    if (handlerOrClassName == null) {
        return null;
    }
    else if (handlerOrClassName instanceof NamespaceHandler) {
        return (NamespaceHandler) handlerOrClassName;
    }
    else {
        String className = (String) handlerOrClassName;
        try {
            Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
            if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
                throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
                        "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
            }
            //实例化Handler
            NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
            //执行初始化方法,指定不同的标签各自使用的解析器
            namespaceHandler.init();
            handlerMappings.put(namespaceUri, namespaceHandler);
            return namespaceHandler;
        }
     .......
    }
}

进到getHandlerMappings方法:

private Map<String, Object> getHandlerMappings() {
    if (this.handlerMappings == null) {
        synchronized (this) {
            if (this.handlerMappings == null) {
                try {
                    Properties mappings =
                            PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Loaded NamespaceHandler mappings: " + mappings);
                    }
                    Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size());
                    CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
                    this.handlerMappings = handlerMappings;
                }
            }
        }
    }
    return this.handlerMappings;
}

读取文件的具体操作就不跟了,回到DefaultNamespaceHandlerResolver#resolve,看看获取到的mapping:

其中一个则是以http://code.alibabatech.com/schema/dubbo 为键, DubboNamespaceHandler为值,因此,当解析dubbo的元素时,则会使用DubboNamespaceHandler

回到delegate.parseCustomElement,并进入到handler.parse中:

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
    return findParserForElement(element, parserContext).parse(element, parserContext);
}

findParserForElement(element, parserContext),查找对应的解析器,即handler.init()中初始化的,然后对应解析器开始解析Element,最终在DubboBeanDefinitionParser#parse中进行构建RootBeanDefinition,并将构建好的RootBeanDefinition加入到容器中,并在容器refresh过程的finishBeanFactoryInitialization(beanFactory)中创建对应实例。

原文地址:https://blog.51cto.com/9587581/2422239

时间: 2024-10-19 03:10:21

Dubbo配置文件解析的相关文章

Spring Boot干货系列:(二)配置文件解析

Spring Boot:配置文件解析   前言 上一篇介绍了Spring Boot的入门,知道了Spring Boot使用"习惯优于配置"(项目中存在大量的配置,此外还内置了一个习惯性的配置,让你无需手动进行配置)的理念让你的项目快速运行起来.所以,我们要想把Spring Boot玩的溜,就要懂得如何开启各个功能模块的默认配置,这就需要了解Spring Boot的配置文件application.properties. 正文 Spring Boot使用了一个全局的配置文件applicat

linuxPAM认证配置文件解析

1.PAM文件 /etc/pam.conf或者/etc/pam.d/ PAM配置文件/lib(64)/security/pam_*.so 可动态加载的PAM service module 2.配置文件格式 /etc/pam.conf:主配置文件 service    type    control    module-path    module-arguments /etc/pam.d/service:服务配置文件 type    control    module-path    modul

MySQL 5.6.24 线上版本配置文件解析

线上MySQL服务器配置文件解析 innodb_buffer_pool_size 非常重要的一个参数,用于配置InnoDB的缓冲池,如果数据库中只有哦Innodb表,则推荐配置量为总内存的75% select  engine,round(sum(data_length + index_length)/1024/1024,1) as 'Total MB' from information_schema.tables  where table_schema not in ('information_

SSH学习之二 OpenSSH配置文件解析

下面是对SSH配置文件的一些选项的分解说明,ssh_config是OpenSSH客户端的配置文件,sshd_config是OpenSSH服务器端的配置文件. ssh_config的内容如下: # This is the ssh client system-wide configuration file.  See ssh_config(5) for more information.  This file provides defaults for users, and the values c

redis概述,特点,与Memached的不同,生产环境主从配置,redis配置文件解析

Redis概述: 是一个基于Key-Value的持久化数据库存储,支持丰富的数据类型,用C语言编写,可基于内存又可持久化的日志型.Key-Value数据库,并提供多种语言的API Redis特点 1.Key-Value健值类型存储 2.支持数据可靠存储及落地 3.单进程单线程高性能服务器 4.单机qps(每秒查询率)可以达到10w 5.适合小数据量高速读写访问 Redis跟Memached的不同 1.Redis可以持久化数据存储 2.性能高很,Redis能支持超过10W每秒的读写频率 3.丰富的

SSH问题:系统启动时,spring配置文件解析失败,报”cvc-elt.1: 找不到元素 &#39;beans&#39; 的声明“异常

现象:spring加载配置文件applicationContext.xml出错,抛出nested exception is og.xml.sax.SAXParseException; lineNumber: 12; columnNumber: 47; cvc-elt.1: 找不到元素 'beans' 的声明r的异常信息. 造成该异常原因有两种: 第一,配置文件头部配置的xsd版本信息不正确,造成解析时出错.spring头部xsd或dtd校验文件的查找分两步,第一先从本地jar包中找,如果找到则用

mybatis配置文件解析原理简略时序图

配置文件解析主要用到XMLConfigBuilder(解析mybatis-config.xml) -->  XMLMapperBuilder(解析mapper.xml) --> XMLStatementBuilder(解析mapper.xml中cache, resultMap等配置信息) -->XMLScriptBuilder(解析mapper.xml中insert update select delete等sql语句节点) 1. 每个SQL语句节点都会生成一个SqlSource,每个S

系统启动时,spring配置文件解析失败,报”cvc-elt.1: 找不到元素 &#39;beans&#39; 的声明“异常

现象:spring加载配置文件applicationContext.xml出错,抛出nested exception is og.xml.sax.SAXParseException; lineNumber: 12; columnNumber: 47; cvc-elt.1: 找不到元素 'beans' 的声明r的异常信息. 造成该异常原因有两种: 第一,配置文件头部配置的xsd版本信息不正确,造成解析时出错.spring头部xsd或dtd校验文件的查找分两步,第一先从本地jar包中找,如果找到则用

WCF中配置文件解析

WCF中配置文件解析 2014-06-14 参考 WCF中配置文件解析 返回 在WCF Service Configuration Editor的使用中,我们通过配置工具自动生成了WCF服务端的config文件.现在我们来看下这个配置文件各个标签的意义: 1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <!-- 这个程序集我们在项目中有引用的 --> 4