Spring 源码学习(1) —— 自定义标签
Spring 工作流程是先加载解析xml配置文件:配置文件中存在默认的标签,也可以自定义标签。解析默认标签调用:
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
解析自定义标签调用:
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
parseCustomElement
下面我们正式开始搞Spring自定义标签:
1.搞一个Bean: 这是一个很普通的pojo, 只是用来接收配置文件。
/**
* @filename: User.java
* @author: Wang Chinda
* @date: 2018-05-21
* @version: v1.0
* @modify_history: -
* 20180521 Wang Chinda create
* 20180521 Wang Chinda modify method()
*/
package com.itdoc.learn.source.custom; /**
* @desc 自定义标签测试类
* @author Wang Chinda
* @create 2018-05-21 14:03
*/
public class User {
private String id;
private String userName;
private String email; public String getId() {
return id;
} public void setId(String id) {
this.id = id;
} 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;
}
}
User
2.定义一个文件描述组件[xml schama difinition (xsd)]: 在classpath下创建一个META-INF文件夹, 在此文件夹下创建一个spring-user.xsd文件。
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.itdoc.com/schema/user"
targetNamespace="http://www.itdoc.com/schema/user"
elementFormDefault="qualified">
<xsd:element name="user">
<xsd:complexType>
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="userName" type="xsd:string" />
<xsd:attribute name="email" type="xsd:string" />
</xsd:complexType>
</xsd:element>
</xsd:schema>
spring-user
targetNamespace="http://www.itdoc.com/schema/user" 和xmlns="http://www.itdoc.com/schema/user"都是自定义的。
文件中的片段意义:
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
显示 schema 中用到的元素和数据类型来自命名空间 "http://www.w3.org/2001/XMLSchema"。同时它还规定了来自命名空间 "http://www.w3.org/2001/XMLSchema" 的元素和数据类型应该使用前缀 xsd
xmlns="http://www.itdoc.com/schema/user"
指出默认的命名空间是 "http://www.itdoc.com/schema/user"
targetNamespace="http://www.itdoc.com/schema/user"
显示被此 schema 定义的元素 (note, to, from, heading, body) 来自命名空间: "http://www.itdoc.com/schema/user"
elementFormDefault="qualified"
指出任何 XML 实例文档所使用的且在此 schema 中声明过的元素必须被命名空间限定
在上面的xsd文件描述中添加一个targetNamespace, 并在这个命名空间中定义了一个name为user的element, user有3个属性id、userName、email, 三个属性均为string类型。
3.创建一个用来解析xsd文件的定义和组件定义的文件并实现BeanDefinitionParser接口。此例中我们继承AbstractSingleBeanDefinitionParser抽象类.

/**
* @filename: UserBeanDefinitionParse.java
* @author: Wang Chinda
* @date: 2018-05-21
* @version: v1.0
* @modify_history: -
* 20180521 Wang Chinda create
* 20180521 Wang Chinda modify method()
*/
package com.itdoc.learn.source.custom; import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element; /**
* @desc 自定义bean定义解析
* @author Wang Chinda
* @create 2018-05-21 14:20
*/
public class UserBeanDefinitionParse extends AbstractSingleBeanDefinitionParser { /**
* Element对应的类
* @param element
* @return
*/
@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"); // 将提取到的数据放入到BeanDefinitionBuilder中, 待完成所有bean的解析后统一注册到beanFactory中
if (StringUtils.hasText(userName)) {
builder.addPropertyValue("userName", userName);
} if (StringUtils.hasText(email)) {
builder.addPropertyValue("email", email);
}
}
}
UserBeanDefinitionParse
4.创建一个Handler文件, 扩展自NamespaceHandlerSupport, 目的是将组件注册到Spring容器中
/**
* @filename: MyNameSpaceHandler.java
* @author: Wang Chinda
* @date: 2018-05-21
* @version: v1.0
* @modify_history: -
* 20180521 Wang Chinda create
* 20180521 Wang Chinda modify method()
*/
package com.itdoc.learn.source.custom; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; /**
* @desc 自定义命名空间控制器
* @author Wang Chinda
* @create 2018-05-21 14:28
*/
public class MyNameSpaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("user", new UserBeanDefinitionParse());
}
}
MyNameSpaceHandler
以上代码功能是当遇到<xxx:user 这样开头的元素, 就会交给UserBeanDefinitionParse去解析。
5.编写spring.handlers和spring.schemas文件, 默认位置是在classpath:/META-INF/文件夹下
注意:
1) 这两个文件名不允许改,若想更改的话,得需要连带更改spring源码文件。
2) 为什么将spring.handlers和spring.schemas放在META-INF文件夹下, 因为Spring默认到这个文件夹中寻找spring.handlers和spring.schemas文件。
spring.handlers:
http\://www.itdoc.com/schema/user=com.itdoc.learn.source.custom.MyNameSpaceHandler
spring.schemas:
http\://www.itdoc.com/schema/user.xsd=META-INF/spring-user.xsd
注意:
1) 冒号用来转译的。
2) 命名空间一定不要写错, 要和targetNamespace中定义的相同。
Spring加载自定义标签的大致流程是遇到自定义标签就会去spring.handler和spring.schemas中去找对应的handler和xsd,进而找到对应的MyNameSpaceHandler以及解析元素的UserBeanDefinitionParse, 从而完成了整个自定义标签的解析。
6.创建测试配置文件, 在文件中引入对应的命名空间及xsd, 便可以使用自定义标签。
<?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:myTag="http://www.itdoc.com/schema/user"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.itdoc.com/schema/user http://www.itdoc.com/schema/user.xsd"> <myTag:user id="customBeanTest" userName="name" email="itdoc@163.com"/> </beans>
7.测试
/**
* @filename: CustomMain.java
* @author: Wang Chinda
* @date: 2018-05-21
* @version: v1.0
* @modify_history: -
* 20180521 Wang Chinda create
* 20180521 Wang Chinda modify method()
*/
package com.itdoc.learn.source.custom; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; /**
* @desc 测试
* @author Wang Chinda
* @create 2018-05-21 14:58
*/
public class CustomMain { public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("test/customTest.xml");
User user = (User) applicationContext.getBean("customBeanTest");
System.out.println(user.getEmail() + " ---- " + user.getUserName());
}
}
控制台显示:

GitHub地址: https://github.com/wcd19901010/spring-01
Spring 源码学习(1) —— 自定义标签的更多相关文章
- spring源码学习之默认标签的解析(一)
继续spring源码的学习之路,现在越来越觉得这个真的很枯燥的,而且我觉得要是自己来看源码,真的看不下去,不是没有耐心,而是真的没有头绪,我觉得结合着书来看,还是很有必要的,最起码大致的流程是能够捋清 ...
- spring源码学习之默认标签的解析(二)
这个是接着上一篇来写,主要是这章内容比较多,还是分开来写吧! 一.AbstractBeanDefinition属性介绍 XML中的所有的属性都可以在GenericBeanDefinition中找到对应 ...
- spring源码研究2 自定义标签实现及使用
1.自定义标签实现及使用参考: http://blog.csdn.net/fighterandknight/article/details/50112701 1)创建一个需要扩展的组件 User.ja ...
- Spring源码学习-容器BeanFactory(四) BeanDefinition的创建-自定义标签的解析.md
写在前面 上文Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签对Spring默认标签的解析做了详解,在xml元素的解析中,Spri ...
- Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签
写在前面 上文Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作中Spring对XML解析后创建了对应的Docum ...
- Spring源码学习
Spring源码学习--ClassPathXmlApplicationContext(一) spring源码学习--FileSystemXmlApplicationContext(二) spring源 ...
- Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作
写在前面 上文 Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件主要讲Spring容器创建时通过XmlBeanDefinitionReader读 ...
- Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...
- spring源码学习之路---IOC初探(二)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章当中我没有提及具体的搭 ...
随机推荐
- tomcat下载、安装
下载 官网地址:https://tomcat.apache.org/download-80.cgi 安装 直接安装即可.安装完毕后Tomcat的目录结构如下: bin:脚本目录 启动脚本:star ...
- Bcp 使用心得【转】
在做这方面研究的时候,的确遇到了不少麻烦. 首先在做bcp的时候,要开通大数据量访问权限 一.基于sql语句的导入导出 如果是基于SQL语句的导入导出,需要使用存储过程“master..xp_cmds ...
- POJ 2540 Hotter Colder(半平面交)
Description The children's game Hotter Colder is played as follows. Player A leaves the room while p ...
- Html5 input placeholder 属性字体颜色修改。
这篇文章主要介绍了有关HTML5 input placeholder 颜色修改方面的知识,需要的朋友可以参考下 Chrome支持input=[type=text]占位文本属性,但下列CSS样式 ...
- Median Weight Bead(最短路—floyed传递闭包)
Description There are N beads which of the same shape and size, but with different weights. N is an ...
- Thunder团队第六周 - Scrum会7
Scrum会议7 小组名称:Thunder 项目名称:i阅app Scrum Master:杨梓瑞 工作照片: 参会成员: 王航:http://www.cnblogs.com/wangh013/ 李传 ...
- 团队Beta阶段事后分析
团队Beta阶段事后分析 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件要解决用户的休闲娱乐问题,为用户提供好玩的模拟经营类的游戏,游戏主题 ...
- thrift多平台安装
thrift支持多语言的RPC,一直都想深入学习了解thrift,最近有空,就上网查了些资料,学习了一下,对它的使用有了一些了解.本篇是写thrift的安装,使用方法会另起一篇来写. 本文使用thri ...
- bootstrap列表添加滚动条
有时候列表中数据过多,导致超出页面,影响视觉感受.这时我们需要添加一个滚动条. 初始状态如图: 代码如下: <ul class="list-group"> <li ...
- CEntOS6.5从启动界面直接进入命令行界面
ctrl + alt + F1 ctrl + alt + F2 ctrl + alt + F3 ctrl + alt + F4 ctrl + alt + F5 ctrl + alt + F6 同时按下 ...