dubbo源码—dubbo自定义spring xml标签
dubbo为了和spring更好的集成,提供了一些xml配置标签,也就是自定义标签
spring自定义标签
spring自定义标签的方式如下:
- 设计配置属性和JavaBean
- 编写xsd文件,校验xml属性和便于编辑器提示
- 编写NamespaceHandler和BeanDefinitionParser解析xml对应的标签
- 编写spring.handlers和spring.schemas串联起所有部件,放在META_INF下面
- 在xml中引入对应的标签就可以使用
dubbo自定义标签
dubbo对应的定义为:
- ApplicationConfig,ModuleConfig,RegistryConfig,MonitorConfig等
- META_INF/dubbo.xsd
- DubboNamespaceHandler,DubboBeanDefinitionParser
- META_INF/spring.handlers,META_INF/spring.schemas
spring在解析xml并加载bean定义的时候,会加载spring用来解析xml标签的handler,spring通过扫描所有类路径下的META_INF/spring.handlers来加载自定义标签的handler,紧接着会调用解析出的handler的init方法
// 类DefaultNamespaceHandlerResolver
public NamespaceHandler resolve(String namespaceUri) {
// 这里namespaceUri = http://code.alibabatech.com/schema/dubbo
// 加载所有的handlers配置,并取出dubbo自定义的handler
Map<String, Object> handlerMappings = getHandlerMappings();
Object handlerOrClassName = handlerMappings.get(namespaceUri);
// ... 省略中间代码
// 实例化handler并缓存起来,然后调用init方法
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
namespaceHandler.init();
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
// ... 省略中间代码
}
private Map<String, Object> getHandlerMappings() {
// ... 省略中间代码
// 这里handlerMappingsLocation = META-INF/spring.handlers
// 加在classpath下所有spring.handlers
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;
// ... 省略中间代码
}
在DubboNamespaceHandler#init方法中添加所有自定义标签对应的parser,将自定义的标签对应的parser添加到NamespaceHandlerSupport#parsers中
public void init() {
// 参数true表示在解析的时候如果没有指定id需要生成一个id
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解析,每一个自定义标签对应一个JavaBean(前面在spring自定义标签的方法中提到),在解析到自定义标签的时候根据标签名称获取到parser解析标签,调用parser.parse方法,parse方法主要作用就是解析标签构造对应JavaBean的RootBeanDefinition,构造好后注入spring容器中
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) && required) {
// 如果没有配置id,先依次试图获取name、interface作为generatedBeanName
if (generatedBeanName == null || generatedBeanName.length() == 0) {
// 如果上面的属性都没有配置则直接获取class的全名作为id
generatedBeanName = beanClass.getName();
}
// 以防该class有其他的实例(比如可以配置多协议,dubbo:protocol),在后面加上一个数字加以区分
id = generatedBeanName;
int counter = 2;
while(parserContext.getRegistry().containsBeanDefinition(id)) {
id = generatedBeanName + (counter ++);
}
}
if (id != null && id.length() > 0) {
// double check
if (parserContext.getRegistry().containsBeanDefinition(id)) {
throw new IllegalStateException("Duplicate spring bean id " + id);
}
// 将BeanDefinition注册到容器
parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
beanDefinition.getPropertyValues().addPropertyValue("id", id);
}
if (ProtocolConfig.class.equals(beanClass)) {
// ... 省略中间代码
// 如果是ProtocolConfig,会找出容器中所有配置了protocol属性的bean,并设置为RuntimeBeanReference
definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));
} else if (ServiceBean.class.equals(beanClass)) {
// ... 省略中间代码
// 如果dubbo:service配置class属性,将ref属性设置为class属性对应的bean
beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
} else if (ProviderConfig.class.equals(beanClass)) {
// 解析dubbo:provider包含的子标签
parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);
} else if (ConsumerConfig.class.equals(beanClass)) {
// 解析dubbo:consumer包含的子标签
parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefinition);
}
// ... 省略中间代码
// 下面的代码就是解析bean属性(比如:parameters、registry等)添加到beanDefinition中
}
总结
dubbo自定义标签都是需要实例化的bean,所以dubbo解析自定义标签的主要工作就是讲bean定义注册到容器中,等getBean(或者依赖解析)的时候进行实例化。
dubbo源码—dubbo自定义spring xml标签的更多相关文章
- Dubbo源码-Dubbo是如何随心所欲自定义XML标签的
叨叨 今天考虑了很久要不要写这篇文章. 距离<Dubbo源码>系列的开篇到现在已经快两个月时间了.当时是想着工作上的RPC框架使用存在一些让人头疼的问题,就来看看Dubbo给出了一套什么样 ...
- dubbo源码分析(一)-从xml到我们认识的Java对象
项目中用的dubbo的挺多的,然后随着自己对dubbo的慢慢深入,自己也希望能够了解dubbo的底层实现,这半年来一直在看dubbo的源码,有点断断续续的,于是准备写一个dubbo源码系列的分析文章, ...
- dubbo源码—dubbo简介
dubbo是一个RPC框架,应用方像使用本地service一样使用dubbo service.dubbo体系架构 上图中的角色: 最重要的是consumer.registry和provider con ...
- dubbo源码学习(二) : spring 自定义标签
做dubbo的配置时很容易发现,dubbo有一套自己的标签,提供给开发者配置,其实每一个标签对应着一个 实体,在容器启动的时候,dubbo会对所有的配置进行解析然后将解析后的内容设置到实体里,最终du ...
- spring源码学习之:xml标签扩展配置例子
在很多情况下,我们需要为系统提供可配置化支持,简单的做法可以直接基于Spring的标准Bean来配置,但配置较为复杂或者需要更多丰富控制的 时候,会显得非常笨拙.一般的做法会用原生态的方式去解析定义好 ...
- 1、Dubbo源码解析--Dubbo如何驱动Spring IOC容器并配合工作的?
首先Spring要注入自己的bean需要在Spring-provider.xml(提供者spring注入文件,名字可能不一样)添加bean注入,其中有dubbo的自定义标签,xml如何识别这些标签?拿 ...
- dubbo源码之一——xml schema扩展
dubbo源码版本:2.5.4 dubbo-parent |----dubbo-config |----dubbo-config-api |----com.alibaba.dubbo.config.* ...
- 【Dubbo源码阅读系列】服务暴露之本地暴露
在上一篇文章中我们介绍 Dubbo 自定义标签解析相关内容,其中我们自定义的 XML 标签 <dubbo:service /> 会被解析为 ServiceBean 对象(传送门:Dubbo ...
- 我找到了Dubbo源码的BUG,同事纷纷说我有点东西
点赞再看,养成习惯,微信搜索[三太子敖丙]关注这个互联网苟且偷生的工具人. 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点.资料以及我的 ...
随机推荐
- java项目log4j日志打印配置
#定义输出级别和输出平台 添加DEBUG表示打印sql 语句 log4j.rootLogger=DEBUG,INFO,ERROR,stdout,R log4j.category.org.spring ...
- Cycling
Cycling Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submi ...
- rsync远程数据同步工具的使用
准备工作 虚拟机1: 192.168.24.41, 用于搭建rsync服务器 虚拟机2: 192.168.26.68, 用于搭建rsync客户端 虚拟机1和虚拟机2均为centos7; 1. 检查虚拟 ...
- jquery IE6 下animate 动画的opacity无效
jquery IE6 下animate 动画的opacity无效,其实是有效的,因为IETester的一个小BUG 原生IE6 没问题...呵呵~~
- H5定位
百度地图javaScript API 一.在html文件中引入 <script src="http://api.map.baidu.com/api?ak=Uk9tDddYkrQImXw ...
- 表空间与数据文件Offline,online的区别
首先明确,表空间与数据文件的关系:Oracle数据库表空间有两种,一种smallfile小文件表空间(默认),另一种bigfile大文件表空间: 默认表空间与数据文件的关系:允许一对多的处理方式,一个 ...
- 解决autocad闪退
1.进入注册表,regedit 2.找到ROOT\installer\Products ,找到以7D2F开头的键值,这里有两个都得删除 3.删除programdata目录下的AutoDesk目录,及f ...
- Java钉钉开发_03_通讯录管理之 人员管理 和 部门管理
一.本节要点 1.通讯录权限 ISV(应用服务商)默认无管理通讯录的权限,企业应用默认有所有通讯录权限. 2.数据传输格式—JSON 请参见: Java_数据交换_fastJSON_01_用法入门 二 ...
- [转载] Linux五种IO模型
转载:http://blog.csdn.net/jay900323/article/details/18141217 Linux五种IO模型性能分析 目录(?)[-] 概念理解 Lin ...
- System.Transactions 事务超时属性
最近遇到一个处理较多数据的大事务,当进行至10分钟左右时,爆出事务超时异常,如果Machine.config中不设置最大超时时间,则默认超时时间为10分钟 MachineSettingsSection ...