spring扩展-自定义命名空间

概述

XML格式中,标签是可以带命名空间的。命名空间主要是解决标签命名冲突的;可能某个标签名在同一个XML中代表两种意思,这是就需要使用命名空间来区分这两种不同的用途。详细的可以去百度XML命名空间。
spring的解析XML时,会分两种情况,一种是默认命名空间标签,spring会正常当做bean来解析;还有一种是带命名空间的标签,比如:

  • <tx:annotation-driven transaction-manager=“transactionManager”></tx:annotation-driven>
  • <aop:config>
    这种带命名空间的标签会有专门的解析器,也可以按照spring 的机制,自定义一个带命名空间的标签,来实现特殊的配置。

带命名空间的标签的解析过程

带命名空间的标签,spring代码中称为(custom tag),即自定义标签。

  1. 走读代码会发现,XML格式配置解析最终会走到
    DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
    下面是相关代码
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
	# 判断该标签是不是默认命名空间,root是<beans>标签
	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);
	}
}
  1. delegate.parseCustomElement就是BeanDefinitionParserDelegate#parseCustomElement方法,代码如下:
# 代码有删减
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
	String namespaceUri = getNamespaceURI(ele);
	NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
	return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

从代码中可以看到,每个不同命名空间都有自己的NamespaceHandler 来进行处理的。

  1. NamespaceHandler是如何注册进去的?
    在这里插入图片描述

xml格式的在加载bean的过程中,会一层层委托下去,最终由BeanDefinitionParserDelegate解析XML生成bean的定义(BeanDefinition)。

2中的代码this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
getNamespaceHandlerResolver最终会获取到DefaultNamespaceHandlerResolver,这个是在XmlBeanDefinitionReader中创建的。
下面贴出DefaultNamespaceHandlerResolver主要的代码:

# 代码有删减
public NamespaceHandler resolve(String namespaceUri) {
	Map<String, Object> handlerMappings = getHandlerMappings();
	Object handlerOrClassName = handlerMappings.get(namespaceUri);
	String className = (String) handlerOrClassName;
	Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
	NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
	namespaceHandler.init();
	return namespaceHandler;
}

private Map<String, Object> getHandlerMappings() {
	# 代码有删减
	# this.handlerMappingsLocation的默认路径为"META-INF/spring.handlers"
	Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
	handlerMappings = new ConcurrentHashMap<>(mappings.size());
    return handlerMappings;
}

从代码中可以看到,自定义标签的handler是配置在META-INF/spring.handlers中的,跟spring的SPI机制很类似。
这样根据这个机制,我们也可以自定义一个标签,并实现对应的NamespaceHandler,配置好spring.handlers文件,就可以实现我们自己的扩展。
我们可以去看一下,spring-tx-xx.jar,这个jar包实现了事务管理器,他可以解析<tx:annotation-driven transaction-manager=“transactionManager”>标签

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值