通常情况下,我们只需要按照系统标签的格式去配置bean即可,但是复杂的情况下,需要我们采取自定义标签。

整体流程

Spring 提供了可扩展 Schema 的支持,这是一个不错的折中方案,扩展 Spring 自定义标签配置大致需要以下几个步骤:

  1. 创建一个需要扩展的组件;
  2. 定义一个 XSD 文件来描述组件内容;
  3. 创建一个文件,实现 BeanDefinitionParser 接口,用来解析 XSD 文件中的定义和组件定义;
  4. 创建一个 Handler 文件,扩展自 NamespaceHandlerSupport,目的是将组件注册到 Spring 容器;
  5. 编写 spring.handlers 和 spring.schemas文件;
  6. 测试使用自定义标签。

    自定义组件

    自定义个组件,用于接收标签的配置 . ```java package cn.lichenghao.customtag;

public class Keyboard { private String name; private String color;

  1. public Keyboard() {
  2. }
  3. public String getName() {
  4. return name;
  5. }
  6. public void setName(String name) {
  7. this.name = name;
  8. }
  9. public String getColor() {
  10. return color;
  11. }
  12. public void setColor(String color) {
  13. this.color = color;
  14. }
  15. @Override
  16. public String toString() {
  17. return "Keyboard{" +
  18. "name='" + name + '\'' +
  19. ", color='" + color + '\'' +
  20. '}';
  21. }

}

  1. <a name="qXigy"></a>
  2. ## 定义 xsd
  3. 定义一个 xsd 文件,来描述我们的组件。可以参考系统自带的写,比如 spring-tx.xsd。<br />这里需要注意格式:http://www.lichenghao.cn/schema/{自定义命名}/spring-{自定义命令},建议前后两个一致。
  4. ```xml
  5. <?xml version="1.0" encoding="UTF-8"?>
  6. <schema xmlns="http://www.w3.org/2001/XMLSchema"
  7. targetNamespace="http://www.lichenghao.cn/schema/mytag/spring-mytag"
  8. xmlns:tns="http://www.lichenghao.cn/schema/mytag/spring-mytag"
  9. elementFormDefault="qualified">
  10. <element name="keyboard">
  11. <complexType>
  12. <attribute name="id" type="string"/>
  13. <attribute name="name" type="string"/>
  14. <attribute name="color" type="string"/>
  15. </complexType>
  16. </element>
  17. </schema>

定义 DefinitionParser

创建 DefinitionParser 来解析组件

  1. package cn.lichenghao.customtag;
  2. import org.springframework.beans.factory.support.BeanDefinitionBuilder;
  3. import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
  4. import org.springframework.util.StringUtils;
  5. import org.w3c.dom.Element;
  6. public class KeyboardDefinitionParser extends AbstractSingleBeanDefinitionParser {
  7. @Override
  8. protected Class<?> getBeanClass(Element element) {
  9. return Keyboard.class;
  10. }
  11. @Override
  12. protected void doParse(Element element, BeanDefinitionBuilder builder) {
  13. String name = element.getAttribute("name");
  14. if (StringUtils.hasText(name)) {
  15. builder.addPropertyValue("name", name);
  16. }
  17. String color = element.getAttribute("color");
  18. if (StringUtils.hasText(color)) {
  19. builder.addPropertyValue("color", color);
  20. }
  21. }
  22. }

定义 NamespaceHandlerSupport

创建 NamespaceHandlerSupport 注册组件

  1. package cn.lichenghao.customtag;
  2. import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
  3. public class MyNameSpaceHandler extends NamespaceHandlerSupport {
  4. @Override
  5. public void init() {
  6. registerBeanDefinitionParser("keyboard", new KeyboardDefinitionParser());
  7. }
  8. }

定义 spring.handlers、spring.schemas

编写配置文件,放在 META-INF 文件夹下。
spring.handlers

  1. http\://www.lichenghao.cn/schema/mytag/spring-mytag=cn.lichenghao.customtag.MyNameSpaceHandler

spring.schemas

  1. http\://www.lichenghao.cn/schema/mytag/spring-mytag.xsd=META-INF/spring-mytag.xsd

启动测试

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:my="http://www.lichenghao.cn/schema/mytag/spring-mytag"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  7. http://www.lichenghao.cn/schema/mytag/spring-mytag
  8. http://www.lichenghao.cn/schema/mytag/spring-mytag.xsd">
  9. <!--自定义标签-->
  10. <my:keyboard id="cherry" name="cherry" color="black" />
  11. </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 文件。

单元测试

  1. @DisplayName("测试自定义标签")
  2. @Test
  3. public void customTagTest() {
  4. ClassPathXmlApplicationContext context
  5. = new ClassPathXmlApplicationContext("customtag/keyboard.xml");
  6. Keyboard keyboard = context.getBean(Keyboard.class);
  7. System.out.println(keyboard);
  8. }

小结

Spring 加载自定义的大致流程是遇到自定义标签然后就去 spring.handlers 和 spring.schemas 中去找对应的 handler 和 XSD,默认位置是/META-NF/ 下,进而有找到对应的 handler 以及解析元素的 Parser,从而完成了整个自定义元素的解析。