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(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章当中我没有提及具体的搭 ...
随机推荐
- Ubuntu14.04下部署FastDFS 5.08+Nginx 1.9.14
最新的版本可以在这里获取,目前下载的最新版本是5.08,更新于2016-02-03.在这里可以找到更多的说明. 下载好后,server端分为两个部分,一个是tracker,一个是storage.顾 ...
- Martian Addition
In the 22nd Century, scientists have discovered intelligent residents live on the Mars. Martians are ...
- 常用web资源
ip相关 新浪:http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js&ip=220.181.38.110 (不带参数本机) ...
- 自定义View 和 ViewGroup
一. 自定义View介绍 自定义View时, 继承View基类, 并实现其中的一些方法. (1) ~ (2) 方法与构造相关 (3) ~ (5) 方法与组件大小位置相关 (6) ~ (9) 方法与触摸 ...
- Alpha 冲刺2
队名:日不落战队 安琪(队长) 今天完成的任务 组织第二次站立式会议. 完成40%个人信息前端界面. 明天的计划 完成剩下的60%个人信息前端界面. 还剩下的任务 个人信息修改前端界面. 遇到的困难 ...
- Web界面和Winform界面生成,代码生成工具
在上面一篇随笔<代码生成工具之界面快速生成>介绍了代码生成工具Database2Sharp的界面生成操作,其中介绍了Web界面(包括列表界面.内容显示.内容编辑界面的生成,另外还介绍了Wi ...
- 数论的欧拉定理证明 & 欧拉函数公式(转载)
欧拉函数 :欧拉函数是数论中很重要的一个函数,欧拉函数是指:对于一个正整数 n ,小于 n 且和 n 互质的正整数(包括 1)的个数,记作 φ(n) . 完全余数集合:定义小于 n 且和 n 互质的数 ...
- MySQL加密算法
1.不可逆加密: PASSWORD(),ENCRYPT(,),MD5(),SHA5(). 2.可逆的加密算法: ENCODE(,) DECODE(,):加密解密字符串.该函数有两个参数:被加密或解 ...
- vue-cli项目里npm安装使用elementUI
第一步:进入到项目目录里 npm i element-ui -S 第二步:在main.js中引入 import ElementUI from 'element-ui' import 'element- ...
- 安装django 提示ImportError: No module named setuptools
安装django前要先安装setuptools 先安装一些必要的包,否则会报错:Python build finished, but the necessary bits to build these ...