当完成从配置文件到 Document 的转换并提取对应的 root 后,将开始了所有元素的解析,而在这一过程
中便开始了默认标签与自定义标签两种格式的区分
当 Spring 拿到一个元素时首先要做的是根据命名空间进行解析,
如果是默认的命名空间,则使用 parseDefaultElement 方法进行元素解析,否则使用 parseCustomElement 方法进行解析
自定义标签使用
扩展 Spring 自定义标签配置大致需要以下几个步骤(前提是要把 Spring Core包加入项目中)
创建一个需要扩展的组件
定义一个 XSD 文件描述组件内容
创建一个文件,实现 BeanDefinitionParser 接口,用来解析 XSD 文件中的定义和组件
定义
创建一个 Handler 文件,扩展自 NamespaceHandlerSupport ,目的是将组件注册到 Spring
容器
编写 Spring.handlers和Spring.schemas 文件
通过自定义标签实现了通过属性的方式将 user 类型的 Bean赋值,在 Spring 中自定义标签非常常用 例如我们熟知的事务标签 tx()
自定义标签解析
是根据对应的 bean 获取对应的命名空间 ,根据命名空间解析对应的处理器 ,然后根据用户自定义的处理器进行解析
获取标签的命名空间
提取自定义标签处理器
如果要使用自定义标签,那么其中一项必不可少的操作就是在 Spring.handlers 文件中配置
命名空间与命名空间处理器的映射关系 只有这样, Spring 才能根据映射关系找到匹配的处理器,
而寻找匹配的处理器就是在上面函数中实现的 当获取到自定义的 NamespaceHandler 之后就可
以进行处理器初始化并解析了
当得到自定义命名空间处理后会马上执行 namespaceHandler.init() 来进行自定义 BeanDefinitionParser的注册 在这里 ,你可以注册多个标签解析器,当前示例中只有支持 <myrnyname:user
的写法,你也可以在这里注册多个解析器,如 <myname:A 、<myname:B等 ,使得 myname 的命名空
间中可以支持多种标签解析
注册后, 命名空间处理器就可以根据标签的不同来调用不同的解析器进行解析
getHandlerMappings 的主要功能就是读取 Spring.handlers配置文件并将配置文件缓存在 map 中
借助了工具类 PropertiesLoaderUtils 对属性 handlerMappingsLocation 进行
了配置文件的读取, handlerMappingsLocation 被默认初始化为“META-INF/Spring.handlers
标签解析
得到了解析器以及要分析的元素后, Spring 就可以将解析工作委托给自定义解析器去解析
了
此时的 handler 已经被实例化成我们自定义的 MyNamespaceHandler 了,而 MyNamespaceHandler 也已经完成了初始化的工作,但是在我们实现的自定义命名空间处理器中并没有实现 parse 方法,所以推断,这个方法是父类中的实现
首先获取在 MyNameSpaceHandler 类中的 init 方法中注册的对应的 UserBeanDefinitionParser 实例,并调用其 parse 方法进行进一步解析。
在这个函数中大部分的代码是用来处理将解析后的 AbstractBeanDefinition 转化为 BeanDefinitionHolder 并注册的功能,而真正
去做解析的事情委托给了函数 parselnternal ,正是这句代码调用了我们自定义的解析函数
在parselnternal 中并不是直接调用自定义的 doParse 函数,而是进行了一系列的数据准备,
包括对 beanClass scope lazylnit 等属性的准备
虽然在实例中我们定义 UserBeanDefinitionParse ,但
是在其中我们只是做了与自己业务逻辑相关的部分 不过我们没做但是并不代表没有,在这个处
理过程中同样也是按照 Spring 中默认标签的处理方式进行,包括创建BeanDefinition 以及进行相
应默认属性的设置,对于这些工作 Spring 都默默地帮我们实现了,只是暴露出一些接口来供用
户实现个性化的业务