一. Spring源码(六):深入自定义标签解析介绍了Spring对自定义标签的解析,这篇文件主要介绍如何自定义标签来完成复杂的业务需求。
二. 先简单回顾一下上篇文件介绍的自定义标签的解析。
1. 获取所有的NamespaceHandler:
通过Spring的SPI加载所有jar包META-INF/spring.handlers下的文件,经过反射创建实例化并调用init初始化方法初始化BeanDefinitionParser解析器存入属性parsers中,然后将NamespaceHandler封装到handlerMappings属性中。
|
2. 根据namespaceUri(http://oss.housihai.com/schema/reyco)获取到具体的NamespaceHandler,然后调用它的parse()方法。
|
3.在parse()方法中先根据标签到parsers属性中获取到具体的BeanDefinitionParser解析类,然后调用BeanDefinitionParser解析类的parse。在parse方法中将标签属性封装到BeanDefinition中,然后注册到Spring容器中。(parsers属性就是我们调用NamespaceHandler的init方法的时候注入的)
|
三. 开始自定义标签:
模拟bean标签注册Bean对象,标签样式如下图:
id:bean的名称 class:beanClass的类型
![]() |
1. 定义META-INF/spring-reyco.xsd文件
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://oss.housihai.com/schema/reyco"
xmlns:tns="http://oss.housihai.com/schema/reyco"
elementFormDefault="qualified">
<element name="reyco">
<complexType>
<attribute name="id" type="string"></attribute>
<attribute name="class" type="string"></attribute>
</complexType>
</element>
</schema>
2. 定义一个命名空间处理器NamespaceHandler,继承NamespaceHandlerSupport并重写init方法。
/**
* @author reyco
* @version v1.0.1
*/
public class ReycoNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("reyco", new ReycoBeanDefinitionParser());
}
}
3.在init方法中需要注册一个BeanDefinitionParser(Bean定义解析器),解析我们的自定义标签。所以需要定义一个BeanDefinitionParser,实现parse方法。
/**
* element的解析器:
* 可以实现@Link(BeanDefinitionParser)接口,也可以继承@Link(BeanDefinitionParser)的子类去实现如:AbstractBeanDefinitionParser、AbstractSingleBeanDefinitionParser
* 我这里通过实现了BeanDefinitionParser接口并手动注册了Bean
* @author reyco
* @version v1.0.1
*/
public class ReycoBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
String beanClassName = element.getAttribute("id");
String beanClass = element.getAttribute("class");
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
AbstractBeanDefinition beanDefinition = builder.getRawBeanDefinition();
try {
beanDefinition.setBeanClassName(beanClassName);
beanDefinition.setBeanClass(Class.forName(beanClass));
BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanDefinition,beanClassName, null);
//注册BeanDefinition对象
BeanDefinitionReaderUtils.registerBeanDefinition(beanDefinitionHolder, parserContext.getRegistry());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return beanDefinition;
}
}
4.编写META-INF/spring.handlers文件,指定我们NamespaceHandler
http\://oss.housihai.com/schema/reyco=com.reyco.tag.core.handlers.ReycoNamespaceHandler
![]() |
5. 编写META-INF/spring.schemas文件
http\://oss.housihai.com/schema/reyco.xsd=META-INF/spring-reyco.xsd
![]() |
6. 编写配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:housihai="http://oss.housihai.com/schema/reyco"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://oss.housihai.com/schema/reyco
http://oss.housihai.com/schema/reyco.xsd">
<housihai:reyco id="testService" class="com.reyco.tag.core.service.TestService"/>
</beans>
7. 让spring可以加载写的配置文件
/**
* @author reyco
* @version v1.0.1
*/
@SpringBootApplication
@ImportResource(locations = { "classpath:spring.xml" })
public class TagApplication {
public static void main(String[] args) {
SpringApplication.run(TagApplication.class, args);
}
}
8. 测试是否可以正常使用,看下图,可以正常打印test说明我们的自定义标签起作用了!
|
最后可以看一下整个项目的目录结构
![]() |
至此,整个Spring自定义标签已经介绍完了...
源码地址https://github.com/sihaihou/customTag
Spring源码(一):深入BeanPostProcessor源码—1
Spring源码(二):深入BeanPostProcessor源码—2
Spring源码(三):深入Spring Bean的生命周期