Spring自定义标签使用及原理

   最近大半年一直在看spring的源码,寻思着需要写点什么,也锻炼下自己文档编写的能力。本篇我们讲解spring自定义标签的使用及原理,分为以下小节进行讲解。

  1. 自定义标签的用途
  2. 自定义标签使用
  3. 自定义标签如何被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自定义标签使用及原理
①spring.schemas是告诉spring容器我们的自定义的xsd文件在哪里,内容如下
Spring自定义标签使用及原理
类似与key=value的形式。如果找不到会去网络上下载。

②我们知道DTD与XSD是spring中最常见的切基础的配置文件,打个比方DTD类似于Java的关键字,而XSD则类似于Java的语法。
而我们自定义XSD文件则是对于我们定义bean对象时可以使用的属性限制或者说支持的那些属性配置,自定义的spring-custom.xsd如下:
Spring自定义标签使用及原理
指定namespace时,请勿使用spring默认前缀。
这里我们定义了一个element属性可以设置id,pointcut.

③Handlers作为自定义标签解析的入口需要在默认文件名称spring.handlers指定,文件内容如下:

这里是我们自定义的NamespaceHandlers.目的是为了注册我们对应标签的解析类;
Spring自定义标签使用及原理
④BeanDefinitionParser
这里我们不直接实现这个接口,我们直接使用他的抽象实现类AbstractSingleBeanDefinitionParser。这里我们获取属性并设置到bean中。
Spring自定义标签使用及原理
Spring自定义标签使用及原理

⑤自定义标签的使用
Spring自定义标签使用及原理
⑥工程代码
点这里
⑦Aop及tx也是通过自定义标签来扩展容器能力的
AOP扩展解析入口为AopNamespaceHandlers
Spring自定义标签使用及原理
声明式事务tx解析入口为:TxNamespaceHandler
Spring自定义标签使用及原理
Context解析入口为:ContextNamespaceHandler
Spring自定义标签使用及原理
以上我们都可以看到我们配置的属性代码中对应的BeanDefinitionParser

3.自定义标签如何被spring解析


    这里涉及到整个spring容器对于xml文件的解析过程,理解起来可能会有点困难,但我会尽量给大家做通俗易懂的介绍。
我们只介绍spring对于配置文件的解析过程,不介绍bean对象的实例化,初始化,及管理过程。

    我们先介绍几个基础知识
①我们经常说的spring容器到底指什么,以及如何存储我们配置bean属性?
基础容器BeanFactory,扩展容器ApplicationContext,他们解析配置文件的过程基本相同。
存储结构为Map<beanName, BeanDefinition>实现为ConcurrentHashMap,也就是说我们最终解析出来的xml文件的会存储到这个数据结构中,这就是我们的容器。

②我们解析出配置问文件用哪个对象来接收存储?
我们知道在抽象对象世界里everything is object.所以我们将bean抽象成了对象,它的顶层接口就是BeanDefinition,而子类包括了ChildBeanDefinitionRootBeanDefinitionGenericBeanDefinition,默认文件解析入Map为GenericBeanDefinition.

③Spring基础标签有哪些?
Spring自定义标签使用及原理
Import, alias, bean, beans

④Spring配置文件的解析入口在哪?
这里介绍两个重要的接口及其实现类
BeanDefinitionReaderBeanDefinitionDocumentReader
对应实现类XmlBeanDefinitionReaderDefaultBeanDefinitionDocumentReader
Spring自定义标签使用及原理
Spring自定义标签使用及原理
⑤自定义标签的解析过程
Spring自定义标签使用及原理
这里最关键的步骤是DefaultBeanDefinitionDocumentReader类中私有方法

Spring自定义标签使用及原理
    上图即显示了默认标签和自定义标签的不同解析方式。
    而自定义标签的解析需要借助Delegates获取namespaceuri然后,加载我们配置的spring.handlers文件内容,获取我们指定好的NamespaceHandler,然后调用parse方法初始化的init方法将BeanDefinitionParser初始化到parsers类型为map容器中,然后我们根据localName获取对应的BeanDefinitionParser,进行element的进一步解析。

    这个过程就完成了自定义标签的文件的解析了。