目录
1.自定义标签具体步骤
2.DEMO例程
2.1 创建User类
2.2 创建自定义解析器UserBeanDefinitionParser
2.3 创建自定义处理器UserNameSpaceHandler
2.4 创建自定义XSD
2.5 创建Spring.handlers 和 Spring.schemas
2.6 测试类 Application
2.7 运行结果及目录结构:
3.我们创建的几个文件是如何关联到一起的
4.Spring是如何做到可扩展的
package com.zoo.customXsd;
/**
* @author liuxiaobai
*/
public class User {
private String userName;
private String passWord;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", passWord='" + passWord + '\'' +
'}';
}
}
package com.zoo.customXsd;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* User标签解析器
* @author dasouche
*/
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class getBeanClass(Element element) {
return User.class;
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
String userName = element.getAttribute("userName");
String passWord = element.getAttribute("passWord");
if(StringUtils.hasText(userName)){
builder.addPropertyValue("userName",userName);
}
if(StringUtils.hasText(passWord)){
builder.addPropertyValue("passWord",passWord);
}
}
}
package com.zoo.customXsd;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
/**
* User标签处理器
* @author dasouche
*/
public class UserNameSpaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("user",new UserBeanDefinitionParser());
}
}
Spring.schemas:
http\://www.en.com/schema/user.xsd=META-INF/user.xsd
Spring.handlers:
http\://www.en.com/schema/user=com.zoo.customXsd.UserNameSpaceHandler
package com.zoo;
import com.zoo.customXsd.User;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author liuxiaobai
*/
public class Application {
public static void main(String[] args) {
AbstractApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User)ac.getBean("user");
System.out.println(user);
ac.registerShutdownHook();
}
}
首先Spring.schemas做了一个版本与本地xsd文件的映射,作用是让Spring优先加载本地xsd文件(毕竟我们写的user.xsd网络上访问不了)。其次Spring.handlers文件中配置了xsd命名空间与对应的处理器的匹配关系,让UserNameSpaceHandler和user.xsd关联到了一起。最后UserNameSpaceHandler代码内部绑定了和UserBeanDefinitionParser的关系。
Spring.schemas关联关系配置在AbstractXmlApplicationContext#loadBeanDefinitions()方法:
一系列的构造函数跟进去,发现在此处配置了PluggableSchemaResolver和spring.schemas的映射关系:
具体调用堆栈:
:63, DelegatingEntityResolver (org.springframework.beans.factory.xml)
:68, ResourceEntityResolver (org.springframework.beans.factory.xml)
loadBeanDefinitions:93, AbstractXmlApplicationContext (org.springframework.context.support)
refreshBeanFactory:137, AbstractRefreshableApplicationContext (org.springframework.context.support)
obtainFreshBeanFactory:674, AbstractApplicationContext (org.springframework.context.support)
refresh:534, AbstractApplicationContext (org.springframework.context.support)
:145, ClassPathXmlApplicationContext (org.springframework.context.support)
:85, ClassPathXmlApplicationContext (org.springframework.context.support)
main:13, Application (com.zoo)
spring.schemas文件信息的读取在PluggableSchemaResolver#getSchemaMappings():
具体调用堆栈:
getSchemaMappings:149, PluggableSchemaResolver (org.springframework.beans.factory.xml)
resolveEntity:116, PluggableSchemaResolver (org.springframework.beans.factory.xml)
resolveEntity:90, DelegatingEntityResolver (org.springframework.beans.factory.xml)
resolveEntity:78, ResourceEntityResolver (org.springframework.beans.factory.xml)
resolveEntity:110, EntityResolverWrapper (com.sun.org.apache.xerces.internal.util)
resolveEntity:1079, XMLEntityManager (com.sun.org.apache.xerces.internal.impl)
resolveDocument:655, XMLSchemaLoader (com.sun.org.apache.xerces.internal.impl.xs)
findSchemaGrammar:2681, XMLSchemaValidator (com.sun.org.apache.xerces.internal.impl.xs)
handleStartElement:2056, XMLSchemaValidator (com.sun.org.apache.xerces.internal.impl.xs)
startElement:816, XMLSchemaValidator (com.sun.org.apache.xerces.internal.impl.xs)
scanStartElement:375, XMLNSDocumentScannerImpl (com.sun.org.apache.xerces.internal.impl)
scanRootElementHook:614, XMLNSDocumentScannerImpl$NSContentDriver (com.sun.org.apache.xerces.internal.impl)
next:3134, XMLDocumentFragmentScannerImpl$FragmentContentDriver (com.sun.org.apache.xerces.internal.impl)
next:867, XMLDocumentScannerImpl$PrologDriver (com.sun.org.apache.xerces.internal.impl)
next:605, XMLDocumentScannerImpl (com.sun.org.apache.xerces.internal.impl)
next:113, XMLNSDocumentScannerImpl (com.sun.org.apache.xerces.internal.impl)
scanDocument:507, XMLDocumentFragmentScannerImpl (com.sun.org.apache.xerces.internal.impl)
parse:867, XML11Configuration (com.sun.org.apache.xerces.internal.parsers)
parse:796, XML11Configuration (com.sun.org.apache.xerces.internal.parsers)
parse:142, XMLParser (com.sun.org.apache.xerces.internal.parsers)
parse:247, DOMParser (com.sun.org.apache.xerces.internal.parsers)
parse:339, DocumentBuilderImpl (com.sun.org.apache.xerces.internal.jaxp)
loadDocument:77, DefaultDocumentLoader (org.springframework.beans.factory.xml)
doLoadDocument:432, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
doLoadBeanDefinitions:390, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
loadBeanDefinitions:338, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
loadBeanDefinitions:310, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
loadBeanDefinitions:188, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:224, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:195, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:257, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:134, AbstractXmlApplicationContext (org.springframework.context.support)
loadBeanDefinitions:98, AbstractXmlApplicationContext (org.springframework.context.support)
refreshBeanFactory:137, AbstractRefreshableApplicationContext (org.springframework.context.support)
obtainFreshBeanFactory:674, AbstractApplicationContext (org.springframework.context.support)
refresh:534, AbstractApplicationContext (org.springframework.context.support)
:145, ClassPathXmlApplicationContext (org.springframework.context.support)
:85, ClassPathXmlApplicationContext (org.springframework.context.support)
main:13, Application (com.zoo)
Spring.handlers配置关系在XmlBeanDefinitionReader#registerBeanDefinitions():
一系列构造函数跟进去,发现在DefaultNamespaceHandlerResolver类配置了和Spring.handlers文件的对应关系:
具体调用堆栈:
:93, DefaultNamespaceHandlerResolver (org.springframework.beans.factory.xml)
createDefaultNamespaceHandlerResolver:552, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
getNamespaceHandlerResolver:540, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
createReaderContext:531, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
registerBeanDefinitions:512, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
doLoadBeanDefinitions:391, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
loadBeanDefinitions:338, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
loadBeanDefinitions:310, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
loadBeanDefinitions:188, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:224, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:195, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:257, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:134, AbstractXmlApplicationContext (org.springframework.context.support)
loadBeanDefinitions:98, AbstractXmlApplicationContext (org.springframework.context.support)
refreshBeanFactory:137, AbstractRefreshableApplicationContext (org.springframework.context.support)
obtainFreshBeanFactory:674, AbstractApplicationContext (org.springframework.context.support)
refresh:534, AbstractApplicationContext (org.springframework.context.support)
:145, ClassPathXmlApplicationContext (org.springframework.context.support)
:85, ClassPathXmlApplicationContext (org.springframework.context.support)
main:13, Application (com.zoo)
Spring.handlers的读取在DefaultNamespaceHandlerResolver#getHandlerMappings():
具体堆栈:
getHandlerMappings:158, DefaultNamespaceHandlerResolver (org.springframework.beans.factory.xml)
resolve:119, DefaultNamespaceHandlerResolver (org.springframework.beans.factory.xml)
parseCustomElement:1400, BeanDefinitionParserDelegate (org.springframework.beans.factory.xml)
parseCustomElement:1384, BeanDefinitionParserDelegate (org.springframework.beans.factory.xml)
parseBeanDefinitions:179, DefaultBeanDefinitionDocumentReader (org.springframework.beans.factory.xml)
doRegisterBeanDefinitions:149, DefaultBeanDefinitionDocumentReader (org.springframework.beans.factory.xml)
registerBeanDefinitions:96, DefaultBeanDefinitionDocumentReader (org.springframework.beans.factory.xml)
registerBeanDefinitions:512, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
doLoadBeanDefinitions:391, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
loadBeanDefinitions:338, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
loadBeanDefinitions:310, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
loadBeanDefinitions:188, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:224, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:195, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:257, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:134, AbstractXmlApplicationContext (org.springframework.context.support)
loadBeanDefinitions:98, AbstractXmlApplicationContext (org.springframework.context.support)
refreshBeanFactory:137, AbstractRefreshableApplicationContext (org.springframework.context.support)
obtainFreshBeanFactory:674, AbstractApplicationContext (org.springframework.context.support)
refresh:534, AbstractApplicationContext (org.springframework.context.support)
:145, ClassPathXmlApplicationContext (org.springframework.context.support)
:85, ClassPathXmlApplicationContext (org.springframework.context.support)
main:13, Application (com.zoo)
配置文件读取完毕,就是最后的标签解析工作了,入口在DefaultBeanDefinitionDocumentReader#parseBeanDefinitions()方法:
继续跟进到BeanDefinitionParserDelegate#parseCustomElement()方法:
这里我们可以看到已经可以拿到我们自定义的handler了,跟进这个resolve方法:
可以看到红框对UserNameSpaceHandler进行了一个反射创建,然后蓝框里调用了UserNameSpaceHandler的init()方法,将UserBeanDefinitionParser注册到了UserNameSpaceHandler中,最后绿框将命名空间和对应的handler对应上。
创建好UserNameSpaceHandler的实例后,可以看到调用了UserNameSpaceHandler的parse方法,然后经过一系列拥有继承关系的parse方法,最终会调用到我们自定义的UserBeanDefinitionParser解析器的parse方法中,从而完成对自定义标签的解析。
具体调用过程:
doParse:21, UserBeanDefinitionParser (com.zoo.customXsd)
doParse:146, AbstractSingleBeanDefinitionParser (org.springframework.beans.factory.xml)
parseInternal:88, AbstractSingleBeanDefinitionParser (org.springframework.beans.factory.xml)
parse:63, AbstractBeanDefinitionParser (org.springframework.beans.factory.xml)
parse:74, NamespaceHandlerSupport (org.springframework.beans.factory.xml)
parseCustomElement:1405, BeanDefinitionParserDelegate (org.springframework.beans.factory.xml)
parseCustomElement:1384, BeanDefinitionParserDelegate (org.springframework.beans.factory.xml)
parseBeanDefinitions:179, DefaultBeanDefinitionDocumentReader (org.springframework.beans.factory.xml)
doRegisterBeanDefinitions:149, DefaultBeanDefinitionDocumentReader (org.springframework.beans.factory.xml)
registerBeanDefinitions:96, DefaultBeanDefinitionDocumentReader (org.springframework.beans.factory.xml)
registerBeanDefinitions:512, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
doLoadBeanDefinitions:391, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
loadBeanDefinitions:338, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
loadBeanDefinitions:310, XmlBeanDefinitionReader (org.springframework.beans.factory.xml)
loadBeanDefinitions:188, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:224, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:195, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:257, AbstractBeanDefinitionReader (org.springframework.beans.factory.support)
loadBeanDefinitions:134, AbstractXmlApplicationContext (org.springframework.context.support)
loadBeanDefinitions:98, AbstractXmlApplicationContext (org.springframework.context.support)
refreshBeanFactory:137, AbstractRefreshableApplicationContext (org.springframework.context.support)
obtainFreshBeanFactory:674, AbstractApplicationContext (org.springframework.context.support)
refresh:534, AbstractApplicationContext (org.springframework.context.support)
:145, ClassPathXmlApplicationContext (org.springframework.context.support)
:85, ClassPathXmlApplicationContext (org.springframework.context.support)
main:13, Application (com.zoo)