一:概述
       在很多情况下,我们需要为系统提供可配置化支持,简单的做法可以直接基于Spring的标准Bean来配置,但配置较为复杂或者需要更多丰富控制的时候,就会显得非常笨拙。一般的做法是用原生态的方式去解析定义好的XML文件,然后转为可配置对象。这种方式可以解决问题,但是实现起来比较繁琐。但是利用Spring 提供了可扩展的Schema,将会非常方便。同样,像Spring自身组件tx,阿里的dubbo也同样是利用了可扩展的schema。
     创建Spring自定义标签通常需要一下几个步骤:

  1. 定义自己所要扩展的组件。
  2. 定义一个XSD文件。
  3. 创建一个类,实现BeanDefinitionParser接口,用来解析XSD文件中定义的组件。
  4. 创建一个Handler,实现NamespaceHandlerSupport,将组件注册到Spring容器中去。
  5. 编写spring.handlers和spring.schemas文件。

如下,我们就根据上门步骤一步步实现我们自定义标签的过程。

(1)创建我们所要扩展的组件,本博文用简单的pojo User类代替,如图所示:

spring 设置自定义 classloader spring 自定义标签_spring自定义标签


(2)编写XSD文件,XSD是XML Schema Definition的缩写,不知道该语法的可自行去w3c学习相关语法,这里推荐一篇博客(xsd文档解释),博主感觉还是蛮不错的,如图,为编写xsd文件。

spring 设置自定义 classloader spring 自定义标签_xml_02


(3)实现BeanDefinitionParser

public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
    @Override
    protected Class getBeanClass(Element element) {
        return User.class;
    }

    @Override
    protected void doParse(Element element, BeanDefinitionBuilder builder) {
        String userName = element.getAttribute("userName");
        String email = element.getAttribute("email");
        if(StringUtils.hasText(userName)){
            builder.addPropertyReference("userName",userName);
        }
        if(StringUtils.hasText(email)){
            builder.addPropertyValue("email",email);
        }
    }
}

(4)扩展NamespaceHandlerSupport接口

/**
 * 扩展 namespaceHandlerSupport借口,将自己的组件注册到spring容器中去
 *
 * @author chenhongwei
 * @date 2019/3/3 17:45
 **/
public class CustomerNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
    }
}

(5)编写spring.handlers和spring.schemas文件.

spring 设置自定义 classloader spring 自定义标签_spring_03


spring 设置自定义 classloader spring 自定义标签_xml_04


如上图所示,该两个文件全都在 META-INF目录i下,其中spring.schemas是告诉spring容器我们的自定义的xsd文件在哪里。

二:测试
自此,自定义标签的步骤已完成,编写测试用例验证
(1) 编写Spring配置文件:

<?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:myname="http://www.chw.com/schema/user"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.chw.com/schema/user http://www.chw.com/schema/user.xsd">

    <myname:user id="testBean"  email="bbb"/>
</beans>

(2)编写测试类:

ApplicationContext cxt = new ClassPathXmlApplicationContext("customer-tag-spring.xml");
  User user = (User) cxt.getBean("testBean");
  System.out.println(user);

测试结构截图:

spring 设置自定义 classloader spring 自定义标签_spring_05


可以看到,我们自己自定义的组件已经被注册到Spring容器中去了。对于Spring容器的解析过程,后续也会有文章进行专门解释。