spring中的自定义标签

  某些情况下,为了给业务系统提供可配置化支持,我们一般会用原生态的方式去解析定义好的XML文件,然后转化为配置对象。这种方式对于简单、单一的配置文件,或者是XML配置格式固定的配置文件,还是比较容易处理的。但是对于一些复杂的、对可扩展性、灵活性要求比较高的场景,使用这种方式去验证、解析就会比较麻烦了。针对这种情况,Spring提供了对用户扩展Schema的支持,这样就可以使用Spring已有的验证、解析工具进行自定义标签的处理了。

  扩展Spring自定义标签配置还是比较简单的,大致需要以下几个步骤:

  1. 创建一个需要扩展的组件类
  2. 定义一个XSD文件,描述组件内容
  3. 创建一个类,实现BeanDefinitionParser接口,用来解析XSD文件中的各种定义以及组件定义
  4. 创建一个Handler类,并继承NamespaceHandlerSupport类,目的是将组件注册到Spring容器
  5. 编写spring.schemas和spring.handlers文件分别指定parser与handler,spring默认会通过这两个文件找到BeanDefinitionParser与NamespaceHandlerSupport

下边通过一个简单的示例来展示一下如何创建一个自定义的标签。

  1. 创建一个普通的POJO类
    public class User {
        private String userName;
        private String email;
        public String getUserName() {
            return userName;
        }
        public void setUserName(String userName) {
            this.userName = userName;
        }
        public String getEmail() {
            return email;
        }
        public void setEmail(String email) {
            this.email = email;
        }
    }

     

  2. 定义一个XSD文件,用来描述组件内容
    <?xml version="1.0" encoding="UTF-8"?>
    <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/schema/user" xmlns:tns="http://www.example.org/schema/user" elementFormDefault="qualified">
        <element name="user">
            <complexType>
                <attribute name="id" type="string"></attribute>
                <attribute name="userName" type="string"></attribute>
                <attribute name="email" type="string"></attribute>
            </complexType>
        </element>
    </schema>

    将XSD文件放在src/main/resources/META-INF下,名称为spring-test.xsd

  3. 创建一个类,实现BeanDefinitionParser接口,用来解析XSD文件中的各种定义和组件定义
    public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser{
        
        @Override
        protected Class<?> getBeanClass(Element element){
            return User.class;
        }
        
        @Override
        protected void doParse(Element element, BeanDefinitionBuilder bean){
            String userName = element.getAttribute("userName");
            String email = element.getAttribute("email");
            if(StringUtils.hasText(userName)){
                bean.addPropertyValue("userName", userName);
            }
            if(StringUtils.hasText(email)){
                bean.addPropertyValue("email", email);
            }
        }
    }

     

  4. 创建一个Handler类,并继承NamesapceHandlerSupport,目的是将组件注册到Spring容器
    public class MyNamespaceHandlerSupport extends NamespaceHandlerSupport{
        @Override
        public void init() {
            registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
        }
    }

     

  5. 目前spring还无法加载我们这些自定义的东西,还需要让spring能够找到并加载我们自定义的东西,这个时候就要用到spring.handlers和spring.schemas文件,因为spring会默认查找src/main/resources/META-INF目录下的这两个文件,来检查是否有用户自定义的标签。
    • spring.schemas
      http\://www.example.org/schema/user.xsd=META-INF/spring-test.xsd

       

    • spring.handlers
      http\://www.example.org/schema/user=chapter04.MyNamespaceHandlerSupport

       

下边测试一下我们自定义的标签

  1. 创建测试的xml配置文件
    <?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.example.org/schema/user"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.example.org/schema/user http://www.example.org/schema/user.xsd">
        <myname:user id="testbean" userName="aaa" email="bbb" />
    </beans>

    这里的过程是,注意第四行“xmlns:myname”,当遇到myname开头的标签时,就会通过xmlns:myname="http://www.example.org/schema/user"找到该标签的命名空间为"http://www.example.org/schema/user",然后通过spring.handlers找到对应的该命名空间的handler为chapter04.MyNamespaceHandlerSupport,然后将名字为user的子标签交由UserBeanDefinitionParser对象进行处理。当需要对xml的元素进行验证时,通过第七行可以找到命名空间对应的xsd的名称http://www.example.org/schema/user.xsd,然后通过spring.schemas找到实际的xsd文件对应的位置META-INF/spring-test.xsd,通过spring-test.xsd对元素进行校验。

  2. 创建测试类
    public class Test {
        public static void main(String[] args) {
            ApplicationContext ac = new ClassPathXmlApplicationContext("beanFactoryTest.xml");
            User user = (User)ac.getBean("testbean");
            System.out.println(user.getUserName() + "," + user.getEmail());
        }
    }

     

posted @ 2017-11-02 23:52  angluil  阅读(299)  评论(0)    收藏  举报