最近大半年一直在看spring的源码,寻思着需要写点什么,也锻炼下自己文档编写的能力。本篇我们讲解spring自定义标签的使用及原理,分为以下小节进行讲解。
- 自定义标签的用途
- 自定义标签使用
-
自定义标签如何被spring解析
1.自定义标签的用途
自定义标签可以说是spring提供的最大、最强的Hook(钩子),通俗的讲就是给后续小伙伴开发组件,提供一个标准公共可拔插”接口”,大家可以理解为手机充电器的工业标准口,为了方便各个充电器生产厂家生产,而制定的标准。
既然说自定义标签如此强大,我们在哪里应用的呢? 我们知道spring发展越来越强大,但核心的组件只有spring-core和spring-beans,那么有些人会问我们经常用的context,aop,tx不是吗?对的,这些都是在核心上做的扩展,而这些扩展恰恰是通过自定义标签实现扩展的,还有一些公共开源组件amq,redis,dubbo等等,他们都利用了自定义标签来扩展,使得spring容器的功能越发强大。
2.自定义标签使用
既然自定义标签用途那么广,那么如何使用自定义标签呢?这里我将带领大家感受下自定义标签的使用。需要的文件(按照spring加载、解析的顺序)有以下五个基本文件:
①spring.schemas
②XSD文件
③spring.handlers
④
NamespaceHandler
⑤
BeanDefinitionParser
⑥最后引入到配置文件中使用。
基本自定义标签需要实现两个关键接口:NamespaceHandlerSupport,BeanDefinitionParser
先看下基本工程代码结构:
①spring.schemas是告诉spring容器我们的自定义的xsd文件在哪里,内容如下
类似与key=value的形式。如果找不到会去网络上下载。
②我们知道DTD与XSD是spring中最常见的切基础的配置文件,打个比方DTD类似于Java的关键字,而XSD则类似于Java的语法。
而我们自定义XSD文件则是对于我们定义bean对象时可以使用的属性限制或者说支持的那些属性配置,自定义的spring-custom.xsd如下:
指定namespace时,请勿使用spring默认前缀。
这里我们定义了一个element属性可以设置id,pointcut.
③Handlers作为自定义标签解析的入口需要在默认文件名称spring.handlers指定,文件内容如下:
这里是我们自定义的NamespaceHandlers.目的是为了注册我们对应标签的解析类;
④BeanDefinitionParser
这里我们不直接实现这个接口,我们直接使用他的抽象实现类
AbstractSingleBeanDefinitionParser
。这里我们获取属性并设置到bean中。
⑤自定义标签的使用
⑥工程代码
点这里
⑦Aop及tx也是通过自定义标签来扩展容器能力的
AOP扩展解析入口为
AopNamespaceHandlers
声明式事务tx解析入口为:
TxNamespaceHandler
Context解析入口为:
ContextNamespaceHandler
以上我们都可以看到我们配置的属性代码中对应的
BeanDefinitionParser
。
3.自定义标签如何被spring解析
这里涉及到整个spring容器对于xml文件的解析过程,理解起来可能会有点困难,但我会尽量给大家做通俗易懂的介绍。
我们只介绍spring对于配置文件的解析过程,不介绍bean对象的实例化,初始化,及管理过程。
我们先介绍几个基础知识
①我们经常说的spring容器到底指什么,以及如何存储我们配置bean属性?
基础容器
BeanFactory
,扩展容器
ApplicationContext
,他们解析配置文件的过程基本相同。
存储结构为
Map<beanName, BeanDefinition>
实现为
ConcurrentHashMap
,也就是说我们最终解析出来的xml文件的会存储到这个数据结构中,这就是我们的容器。
②我们解析出配置问文件用哪个对象来接收存储?
我们知道在抽象对象世界里everything is object.所以我们将bean抽象成了对象,它的顶层接口就是
BeanDefinition
,而子类包括了
ChildBeanDefinition
,
RootBeanDefinition
,
GenericBeanDefinition
,默认文件解析入Map为
GenericBeanDefinition
.
③Spring基础标签有哪些?
Import, alias, bean, beans
④Spring配置文件的解析入口在哪?
这里介绍两个重要的接口及其实现类
BeanDefinitionReader
与
BeanDefinitionDocumentReader
对应实现类
XmlBeanDefinitionReader
、
DefaultBeanDefinitionDocumentReader
⑤自定义标签的解析过程
这里最关键的步骤是
DefaultBeanDefinitionDocumentReade
r类中私有方法
上图即显示了默认标签和自定义标签的不同解析方式。
而自定义标签的解析需要借助Delegates获取namespaceuri然后,加载我们配置的spring.handlers文件内容,获取我们指定好的
NamespaceHandler
,然后调用parse方法初始化的init方法将
BeanDefinitionParser
初始化到parsers类型为map容器中,然后我们根据localName获取对应的
BeanDefinitionParser
,进行element的进一步解析。
这个过程就完成了自定义标签的文件的解析了。