上一篇讲了Spring对默认标签的解析,Spring提供了很多属性,可以供开发者根据不同情况使用。绝大多数情况下,这些功能就已经足够了。但是,当用户有更特殊的需求,又或者很多公司自己实现的服务治理框架有一些自定义的需求是spring默认属性无法提供,或者是有更好得实现方式时,一种方式是像Spring一样用原生态的方式去解析定义好的XML文件,然后转化为配置对象,但这样实现起来比较复杂,还有一种方式就是通过Spring提供的可扩展Schema的支持,扩展自定义标签。

扩展自定义标签大致需要以下几个步骤:

1、创建一个需要扩展的组件

2、定义一个.xsd文件描述组件的内容

3、创建一个文件实现BeanDefinitionParser接口,用来解析xsd文件中的定义和组件的含义

4、创建一个handle文件,实现NamespaceHandleSupport,将组件和解析类注册到spring中

5、编写spring.handlers和spring.schemas

首先我们创建一个简单的pojo

package com.wuzhe.spring.test;

public class User {
private String userName; public String getUserName() {
return userName;
} public void setUserName(String userName) {
this.userName = userName;
}
}

第二步,新建一个xsd文件描述自定义的标签

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
xmlns="http://www.test.com/user"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
targetNamespace="http://www.test.com/user"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans" />
<xsd:element name="user">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="userName" type="xsd:string" />
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>

这里定义了一个新的命名空间targetNamespace:http://www.test.com/user  并定义了自定义标签user的属性等信息。

接下来就需要定义解析自定义标签,将其转化为beanDefinition了。spring通过实现BeanDefinitionParser接口来解析自定义标签。

package com.wuzhe.spring.test;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.w3c.dom.Element; 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");
bean.addPropertyValue("userName", userName);
}
}

这里只是简单地将自定义标签user中的userName属性,通过set注入到bean中。所以在beanDefinition添加了对应的PropertValue。

定义好了解析标签的过程,接下来就要在spring中注册这个标签和解析器的联系,这样spring在解析对应自定义标签时就知道用哪个解析器去解析它。

spring中通过扩展NamespaceHandlerSupport来实现这一功能。

package com.wuzhe.spring.test;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

public class Handler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
}
}

最后我们需要编写spring.handlers和spring.schemas这两个文件。这两个文件的功能是在解析xml文件时,一旦遇到自定义标签,就会通过这两个文件找到对应的xsd文件和对应的Handler,然后在handler中注册的对应标签和解析器来解析自定义标签。

这两个文件的默认位置是在resource下的META-INF文件夹下

spring.handlers

http\://www.test.com/user=com.wuzhe.spring.test.Handler

spring.schemas

http\://www.test.com/user.xsd=META-INF/user.xsd

这里http后的\实际上是为了转义冒号的。另外需要特别注意xsd文件和handler类的路径一定不能错。

到这里自定义标签的准备工作就已经完成了。我们可以写一个测试demo

首先容器的配置文件

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cutesource="http://www.test.com/user"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.test.com/user http://www.test.com/user.xsd">
<cutesource:user id="testUser" userName="haha"/>
</beans>

这里使用了自定义的标签user,设置了属性userName的值

写个测试类

public class Main {
public static void main(String[] args) {
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("user.xml"));
User user = (User) beanFactory.getBean("testUser");
System.out.println(user.getUserName());
}
}

我们发现通过自定义标签的方式,成功获取了user实例,并且这个实例的userName属性被设置为了haha。说明我们的自定义配置生效了。

Spring源码学习(3)—— 自定义标签的更多相关文章

  1. Spring 源码学习(1) —— 自定义标签

    Spring 工作流程是先加载解析xml配置文件:配置文件中存在默认的标签,也可以自定义标签.解析默认标签调用: private void parseDefaultElement(Element el ...

  2. spring源码学习之默认标签的解析(一)

    继续spring源码的学习之路,现在越来越觉得这个真的很枯燥的,而且我觉得要是自己来看源码,真的看不下去,不是没有耐心,而是真的没有头绪,我觉得结合着书来看,还是很有必要的,最起码大致的流程是能够捋清 ...

  3. spring源码学习之默认标签的解析(二)

    这个是接着上一篇来写,主要是这章内容比较多,还是分开来写吧! 一.AbstractBeanDefinition属性介绍 XML中的所有的属性都可以在GenericBeanDefinition中找到对应 ...

  4. spring源码研究2 自定义标签实现及使用

    1.自定义标签实现及使用参考: http://blog.csdn.net/fighterandknight/article/details/50112701 1)创建一个需要扩展的组件 User.ja ...

  5. Spring源码学习-容器BeanFactory(四) BeanDefinition的创建-自定义标签的解析.md

    写在前面 上文Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签对Spring默认标签的解析做了详解,在xml元素的解析中,Spri ...

  6. Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签

    写在前面 上文Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作中Spring对XML解析后创建了对应的Docum ...

  7. Spring源码学习

    Spring源码学习--ClassPathXmlApplicationContext(一) spring源码学习--FileSystemXmlApplicationContext(二) spring源 ...

  8. Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作

    写在前面 上文 Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件主要讲Spring容器创建时通过XmlBeanDefinitionReader读 ...

  9. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

    Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...

  10. spring源码学习之路---IOC初探(二)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章当中我没有提及具体的搭 ...

随机推荐

  1. scrapy流程图

    refer:https://blog.yongli1992.com/2015/02/08/python-scrapy-module/ 这里是一张Scrapy架构图的展示.Scrapy Engine负责 ...

  2. Linux基础命令---lpstat查看打印任务

    lpstat lpstat指令用来显示当前任务.打印机的状态.如果没有参数,那么就显示打印队列. 此命令的适用范围:RedHat.RHEL.Ubuntu.CentOS.Fedora.openSUSE. ...

  3. mysql日期操作

    一.获取当前日期时间 1.1.获得当前日期+时间(date+time)函数:now() 1.2.获取当前日期+时间(date+time)函数:sysdate() 注:二者类拟,不同在于now()在执行 ...

  4. Qml文件的两种加载方式

    一种是QQmlApplicationEngine搭配Window,例如: #include <QGuiApplication> #include <QQmlApplicationEn ...

  5. oracel数据库主键自增

    -- Create sequence create sequence FILE_ID_SEQ   主键名(自增列) minvalue 1         起始 maxvalue 99999     最 ...

  6. 每天一个Linux命令 10

    文件处理命令:ln命令名称:ln 命令英文原意:link语法: ln -s [原文件] [目标文件] -s 创建软连接功能描述:生成链接文件 #ln -s /etc/issue /tmp/issue. ...

  7. 怎样从外网访问内网Tornado

    外网访问内网Tornado 本地安装了Tornado,只能在局域网内访问,怎样从外网也能访问本地Tornado? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Tornado 默认安装 ...

  8. zabbix 配置本地邮箱报警

    Centos 6.5, Zabbix 3.0.4 后台配置email 浏览器登录zabbix后台,Administration -> Media types -> Email: 比较简单的 ...

  9. 剑指offer(8)跳台阶

    题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法. 题目分析 题目很简单,稍微分析就知道这是斐波那契数列,所以可以动态规划来做 a.如果两种跳法,1阶 ...

  10. JS设计模式(7)组合模式

    什么是组合模式? 定义:1.将对象组合成树形结构以表示"部分-整体"的层次结构.2.组合模式使得用户对单个对象和组合对象的使用具有一致性.3.无须关心对象有多少层,调用时只需在根部 ...