某些情况下,为了给业务系统提供可配置化支持,我们一般会用原生态的方式去解析定义好的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());
    }
    }

spring中的自定义标签的更多相关文章

  1. 在jsp页面中使用自定义标签

    在某些场景中,自定义标签可封装大量代码,使页面变得更简洁,标签也可以很方便地在不同页面中实现通用而不必去粘贴大量的js代码.现在把最近做的一个自定义标签在这里总结一下.首先总结一下关于自定义标签的一些 ...

  2. springbank 开发日志 Spring启动过程中对自定义标签的处理

    这篇随笔的许多知识来源于:http://www.importnew.com/19391.html 之所以会去看这些东东,主要是希望能够模仿spring mvc的处理流程,做出一套合理的交易处理流程. ...

  3. Spring源码分析(九)解析默认标签中的自定义标签元素

    摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 到这里我们已经完成了分析默认标签的解析与提取过程,或许涉及的内容太多,我 ...

  4. spring源码-自定义标签-4

    一.自定义标签,自定义标签在使用上面相对来说非常常见了,这个也算是spring对于容器的拓展.通过自定义标签的方式可以创造出很多新的配置方式,并且交给容器直接管理,不需要人工太多的关注.这也是spri ...

  5. 在django中使用自定义标签实现分页功能

    效果演示: github地址:https://github.com/mncu/django_projects/tree/master/django_projects/pagination_test 本 ...

  6. javaWeb 在jsp中 使用自定义标签输出访问者IP

    1.java类,使用简单标签,jsp2.0规范, 继承 SimpleTagSupport public class ViewIpSimpleTag extends SimpleTagSupport { ...

  7. spring整合freemarker 自定义标签

    1.自定义标签实现 TemplateDirectiveModel 接口 2.spring 配置,注意标红的两行 <bean id="freemarkerConfig" cla ...

  8. Spring中的p标签(转)good

    Spring的p标签是基于XML Schema的配置方式,目的是为了简化配置方式. 在XML文件头部添加xmlns:p="http://www.springframework.org/sch ...

  9. spring中增加自定义配置支持

    spring.schemas 在使用spring时,我们会首先编写spring的配置文件,在配置文件中,我们除了使用基本的命名空间http://www.springframework.org/sche ...

随机推荐

  1. 【转】嵌入式C语言调试开关

    在调试程序时,经常会用到assert和printf之类的函数,我最近做的这个工程里就有几百个assert,在你自认为程序已经没有bug的时候,就要除去这些调试代码,应为系统在正常运行时这些用于调试的信 ...

  2. LINUX 笔记-DU 和 DF

    du(disk usage)搜索文件统计文件大小 1.显示指定文件所占空间 du file1 file2 2.显示指定目录占的空间 du dir 3.只显示总和大小 du -s 4.以方便格式显示 d ...

  3. Python学习笔记(二)-Python文件类型及编程模式

    Python环境搭建:linux,Windows... Linux下:[root@localhost StudyPython]# python #进入交互模式Python 2.7.11 (defaul ...

  4. 安利一波那个叫做 hutool 的通用工具类库

    摘自3.1.1版本作者发布原话,当时看到有点说不上的情绪,为作者的坚持.热爱点个赞. 已经想不起来是怎样结识 Hutool 的,但 Hutool 伴随几个项目的推进,获得了同事一致好评. 没经过实践和 ...

  5. Ardupilot设备驱动 IIC、SPI、USART

    设备代码层次结构 ​ Ardupilot设备驱动代码的层次结构采用 前端实现 和 后端实现 分割,前端库主要供机器代码层调用,后端库主要供前端调用.这里前端可以理解为应用层,后端理解为驱动层,前端调用 ...

  6. ubuntu中python3.4安装pip

    这两天碰到在ubuntu中安装pip的问题. 第一种方法 用百度搜索了一下,基本上都是这个命令: sudo apt-get install python3-pip 但是,用这条命令下载速度特别慢. 第 ...

  7. 使用Lock锁生产者消费者模式

    package com.java.concurrent; import java.util.concurrent.locks.Condition; import java.util.concurren ...

  8. GCC 中的编译器堆栈保护技术

    GCC 中的编译器堆栈保护技术 前几天看到的觉得不错得博客于是转发了,但这里我补充一下一些点. GCC通过栈保护选项-fstack-protector-all编译时额外添加两个符号,__stack_c ...

  9. 【OpenCV】通过ROI区域以及掩码实现图像叠加

    在图像处理领域,我们常常需要设置感兴趣区域(ROI,region of interest),来专注或者简化我们的工作过程 .也就是从图像中选择的一个图像区域,这个区域是我们图像分析所关注的重点.我们圈 ...

  10. Lucene搜索引擎例子demo

    一.导入相应的jar包 KAnalyzer3.2.0Stable.jar lucene-analyzers-3.0.1.jar lucene-core-3.0.1.jar lucene-highlig ...