上一篇讲了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. WebForm跨页面传值取值、C#服务端跳转页面、 Button的OnClientClick属性和超链接点击弹出警示框

    一.跨页面传值和取值: 1.QueryString - url传值,地址传值 优缺点:不占用服务器内存:保密性差,传递长度有限. 通过跳转页面路径进行传值方式: href="地址?key=v ...

  2. Windwos Live Writer插件指南

    Windows Live Writer 即(WLW) 是一个免费的桌面应用程序,可以用于发布博客. 官网下载地址:https://www.microsoft.com/zh-CN/download/de ...

  3. python locust 性能测试:locsut参数化-保证并发测试数据唯一性,不循环取数据

    from locust import TaskSet, task, HttpLocustimport queue class UserBehavior(TaskSet): @task def test ...

  4. 常见的python的unittest用法

    python的unittest好处是通过python脚本编写用例,每个用例可以单独调试初始化和清理动作,因为都是用例都是代码所以调试起来也很方便:它的缺点是得先学会python,难易程度见仁见智吧,对 ...

  5. topcoder srm 565 div1

    problem1 link $f[i][j]$表示经过前$i$个怪物之后,花费$j$个硬币可以得到的最大值. problem2 link 设$nim[i]$表示数字$i$的nim值.那么题目就是求有多 ...

  6. JS求任意字符串中出现最多的字符以及出现的次数

    我爱撸码,撸码使我感到快乐!大家好,我是Counter本节讲讲如何利用JS来查找任意给定的字符串,求字符串中出现次数最多的字符,出现的次数.直接上代码了,该注释的都注释啦.非常轻松加愉快.效果如下: ...

  7. NFS笔记

    NFS:Network File System (内核空间文件系统) ## 文件系统在内核空间,用户写数据-->系统调用 内核空间 硬件的操作   read()函数 write()函数 :过程调 ...

  8. P3346 [ZJOI2015]诸神眷顾的幻想乡

    思路 注意到叶子节点(度数为1)只有20个,可以分别以这20个节点为根,把所有子串插入SAM中,统计最后的本质不同的子串个数 所以就是广义SAM了 然后注意要判断一下有无重复插入 代码 #includ ...

  9. Java 批量导入大量数据

    项目上线测试.产品说导入太慢了,一样的数据量另外一个系统只需要1分钟,我们要5分钟.... 开始以为是因为POI在解析07版本的Excel时候,因为数据量太多所以慢了,后面看下日志,发现是在入库的时候 ...

  10. 使用vue.js + laravel开发单页面应用

    最近学了vuejs和laravel,然后顺便就撸了简单的demo,这里将会根据这个demo介绍下如何使用vuejs+laravel开发一个简单的单页面应用,demo的github地址是https:// ...