Dubbo和Spring结合配置文件内容解析为bean的过程
2017-09-21 11:36
573 查看
Dubbo 现在已经被很多公司广泛的使用,Dubbo的使用和特性本篇不做讲解,本篇讲解一下Dubbo和Spring结合配置文件内容解析为bean的过程!
Dubbo是结合Spring来进行使用的,其中bean依赖Spring的IOC容器进行管理。Spring默认的Bean加载机制肯定是不能去加载Dubbo提供的Bean,那么Dubbo中的Bean是如何加载到Spring 容器的呢?下面进行介绍:
从配置文件内容中我们可以看出:
由于Spring提供了可扩展Schema的支持,Dubbo有自己的schema 文件!
xmlns:dubbo=”http://code.alibabatech.com/schema/dubbo”指定Dubbo自定义Schema,xsi:schemaLocation用来指定xsd文件! XSD - < schema > 元素 -w3school
Dubbo有一些自定义的标签,如
Web项目,在web.xml中指定加载文件地址
Spring容器在启动的时候,会读取到Spring默认的一些schema以及Dubbo自定义的schema,每个schema都会对应一个自己的NamespaceHandler,NamespaceHandler里面通过BeanDefinitionParser来解析配置信息并转化为需要加载的bean对象!
下面通过分析ClassPathXmlApplicationContext 加载和解析applicationProvider.xml过程!
2、Spring加载Dubbo配置文件解析过程
在AbstractXmlApplicationContext的loadBeanDefinitions方法中使用XmlBeanDefinitionReader. loadBeanDefinitions加载applicationProvider.xml文件
在DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法中,对加载的applicationProvider.xm文件元素使用BeanDefinitionParserDelegate对象进行解析
进入BeanDefinitionParserDelegate 中的 parseCustomElement 方法中
调用resolve()方法,处理
遇到dubbo名称空间 ,首先会调用DubboNamespaceHandler init 进行初始化操作,代码如下
根据不同的XML节点,会委托NamespaceHandlerSupport找出合适的BeanDefinitionParser,其中Dubbo所有的标签都使用 DubboBeanDefinitionParser进行解析,基于一对一属性映射,将XML标签解析为Bean对象。
上面的applicationProvider.xml转换后大概是下面这个样子:
通过DubboBeanDefinitionParser的 parse会将class信息封装成BeanDefinition,然后将BeanDefinition再放进DefaultListableBeanFactory的beanDefinitionMap中。
最后通过Spring bean 的加载机制进行加载!
欢迎访问我的csdn博客,愿我们一同成长!
“不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!”
博客首页:http://blog.csdn.net/u010648555
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>
从配置文件内容中我们可以看出:
由于Spring提供了可扩展Schema的支持,Dubbo有自己的schema 文件!
xmlns:dubbo=”http://code.alibabatech.com/schema/dubbo”指定Dubbo自定义Schema,xsi:schemaLocation用来指定xsd文件! XSD - < schema > 元素 -w3school
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
相关文章推荐
- 学习笔记:springmvc4.3源码学习:spring解析配置文件过程
- spring配置文件中非bean标签的原理解析
- Spring配置文件解析-Bean
- Spring4.3.x 浅析xml配置的解析过程(4)——解析bean标签及其所有子标签
- spring --MethodInvokingFactoryBean 配置文件解析
- spring源码解析-从xml配置文件中获取bean
- Spring 源码 之 配置文件中的Bean在Spring中的创建过程
- Spring配置文件解析--bean属性
- spring源码(3)之解析配置文件的过程
- 模拟Spring中applicationContext.xml配置文件初始化bean的过程
- 快速上手Spring--3. 加载Bean的配置文件
- .NET配置文件解析过程详解
- spring中读取xml配置文件、获取bean的几种方式
- Spring bean配置中属性值由String到实际类型的动态转化过程及PropertyEditor类的应用
- .NET配置文件解析过程详解(二)
- 快速上手Spring 加载Bean配置文件
- 关于hibernate与spring的结合使用中的配置文件
- [转]C# 解析配置文件内容 System.Configuration
- 【转】.NET配置文件解析过程详解(二)
- SPRING里的配置文件里<ref local=""和<ref bean=""区别