通常情况下,我们只需要按照系统标签的格式去配置bean即可,但是复杂的情况下,需要我们采取自定义标签。
整体流程
Spring 提供了可扩展 Schema 的支持,这是一个不错的折中方案,扩展 Spring 自定义标签配置大致需要以下几个步骤:
- 创建一个需要扩展的组件;
- 定义一个 XSD 文件来描述组件内容;
- 创建一个文件,实现 BeanDefinitionParser 接口,用来解析 XSD 文件中的定义和组件定义;
- 创建一个 Handler 文件,扩展自 NamespaceHandlerSupport,目的是将组件注册到 Spring 容器;
- 编写 spring.handlers 和 spring.schemas文件;
- 测试使用自定义标签。
自定义组件
自定义个组件,用于接收标签的配置 . ```java package cn.lichenghao.customtag;
public class Keyboard { private String name; private String color;
public Keyboard() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Keyboard{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
'}';
}
}
<a name="qXigy"></a>
## 定义 xsd
定义一个 xsd 文件,来描述我们的组件。可以参考系统自带的写,比如 spring-tx.xsd。<br />这里需要注意格式:http://www.lichenghao.cn/schema/{自定义命名}/spring-{自定义命令},建议前后两个一致。
```xml
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.lichenghao.cn/schema/mytag/spring-mytag"
xmlns:tns="http://www.lichenghao.cn/schema/mytag/spring-mytag"
elementFormDefault="qualified">
<element name="keyboard">
<complexType>
<attribute name="id" type="string"/>
<attribute name="name" type="string"/>
<attribute name="color" type="string"/>
</complexType>
</element>
</schema>
定义 DefinitionParser
创建 DefinitionParser 来解析组件
package cn.lichenghao.customtag;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
public class KeyboardDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
return Keyboard.class;
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
String name = element.getAttribute("name");
if (StringUtils.hasText(name)) {
builder.addPropertyValue("name", name);
}
String color = element.getAttribute("color");
if (StringUtils.hasText(color)) {
builder.addPropertyValue("color", color);
}
}
}
定义 NamespaceHandlerSupport
创建 NamespaceHandlerSupport 注册组件
package cn.lichenghao.customtag;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
public class MyNameSpaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("keyboard", new KeyboardDefinitionParser());
}
}
定义 spring.handlers、spring.schemas
编写配置文件,放在 META-INF 文件夹下。
spring.handlers
http\://www.lichenghao.cn/schema/mytag/spring-mytag=cn.lichenghao.customtag.MyNameSpaceHandler
spring.schemas
http\://www.lichenghao.cn/schema/mytag/spring-mytag.xsd=META-INF/spring-mytag.xsd
启动测试
<?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:my="http://www.lichenghao.cn/schema/mytag/spring-mytag"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.lichenghao.cn/schema/mytag/spring-mytag
http://www.lichenghao.cn/schema/mytag/spring-mytag.xsd">
<!--自定义标签-->
<my:keyboard id="cherry" name="cherry" color="black" />
</beans>
xmlns:my=”http://www.lichenghao.cn/schema/mytag/spring-mytag“ 自定义标签前缀,可以是任何内容。
http://www.lichenghao.cn/schema/mytag/spring-mytag、
http://www.lichenghao.cn/schema/mytag/spring-mytag.xsd
映射到 spring.handlers 文件和 spring.schemas 文件。
单元测试
@DisplayName("测试自定义标签")
@Test
public void customTagTest() {
ClassPathXmlApplicationContext context
= new ClassPathXmlApplicationContext("customtag/keyboard.xml");
Keyboard keyboard = context.getBean(Keyboard.class);
System.out.println(keyboard);
}
小结
Spring 加载自定义的大致流程是遇到自定义标签然后就去 spring.handlers 和 spring.schemas 中去找对应的 handler 和 XSD,默认位置是/META-NF/ 下,进而有找到对应的 handler 以及解析元素的 Parser,从而完成了整个自定义元素的解析。