Spring中的可扩展点(一)自定义标签
  yIqmAAsdee9S 2023年11月02日 73 0


目录

​​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是如何做到可扩展的​​


1.自定义标签具体步骤

  1. 创建一个需要被自定义标签解析的bean
  2. 创建一个标签解析器Parser,继承自 AbstractSingleBeanDefinitionParser ,用来解析 XSD 中的标签。
  3. 创建一个标签处理器Handler,继承自 NamespaceHandlerSupport, 并实现其init()方法
  4. 创建一个自定义的 XSD 描述文件
  5. 编写 Spring.handlers 和 Spring.schemas 文件,用于引导spring加载对应标签处理器

2.DEMO例程

2.1 创建User类

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 + '\'' +
'}';
}
}

2.2 创建自定义解析器UserBeanDefinitionParser

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);
}
}
}

2.3 创建自定义处理器UserNameSpaceHandler

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());
}
}

2.4 创建自定义XSD

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.en.com/schema/user"
elementFormDefault="qualified">

<xs:element name="user">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="id" type="xs:string"/>
<xs:attribute name="userName" type="xs:string"/>
<xs:attribute name="passWord" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>

</xs:schema>

2.5 创建Spring.handlers 和 Spring.schemas

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

2.6 测试类 Application

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();
}
}

2.7 运行结果及目录结构:

Spring中的可扩展点(一)自定义标签_spring3.我们创建的几个文件是如何关联到一起的

        首先Spring.schemas做了一个版本与本地xsd文件的映射,作用是让Spring优先加载本地xsd文件(毕竟我们写的user.xsd网络上访问不了)。其次Spring.handlers文件中配置了xsd命名空间与对应的处理器的匹配关系,让UserNameSpaceHandler和user.xsd关联到了一起。最后UserNameSpaceHandler代码内部绑定了和UserBeanDefinitionParser的关系。

4.Spring是如何做到可扩展的

        Spring.schemas关联关系配置在AbstractXmlApplicationContext#loadBeanDefinitions()方法:

Spring中的可扩展点(一)自定义标签_后端_02

        一系列的构造函数跟进去,发现在此处配置了PluggableSchemaResolver和spring.schemas的映射关系:

Spring中的可扩展点(一)自定义标签_xml_03

Spring中的可扩展点(一)自定义标签_java_04

具体调用堆栈:

<init>:63, DelegatingEntityResolver (org.springframework.beans.factory.xml)
<init>: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)
<init>:145, ClassPathXmlApplicationContext (org.springframework.context.support)
<init>:85, ClassPathXmlApplicationContext (org.springframework.context.support)
main:13, Application (com.zoo)

        spring.schemas文件信息的读取在PluggableSchemaResolver#getSchemaMappings(): Spring中的可扩展点(一)自定义标签_spring_05

具体调用堆栈:

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)
<init>:145, ClassPathXmlApplicationContext (org.springframework.context.support)
<init>:85, ClassPathXmlApplicationContext (org.springframework.context.support)
main:13, Application (com.zoo)

        Spring.handlers配置关系在XmlBeanDefinitionReader#registerBeanDefinitions():

Spring中的可扩展点(一)自定义标签_后端_06

        一系列构造函数跟进去,发现在DefaultNamespaceHandlerResolver类配置了和Spring.handlers文件的对应关系:

Spring中的可扩展点(一)自定义标签_spring_07Spring中的可扩展点(一)自定义标签_apache_08

具体调用堆栈:

<init>: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)
<init>:145, ClassPathXmlApplicationContext (org.springframework.context.support)
<init>:85, ClassPathXmlApplicationContext (org.springframework.context.support)
main:13, Application (com.zoo)

        Spring.handlers的读取在DefaultNamespaceHandlerResolver#getHandlerMappings():

Spring中的可扩展点(一)自定义标签_后端_09

具体堆栈:

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)
<init>:145, ClassPathXmlApplicationContext (org.springframework.context.support)
<init>:85, ClassPathXmlApplicationContext (org.springframework.context.support)
main:13, Application (com.zoo)

        配置文件读取完毕,就是最后的标签解析工作了,入口在DefaultBeanDefinitionDocumentReader#parseBeanDefinitions()方法:

Spring中的可扩展点(一)自定义标签_apache_10

        继续跟进到BeanDefinitionParserDelegate#parseCustomElement()方法:

Spring中的可扩展点(一)自定义标签_java_11

        这里我们可以看到已经可以拿到我们自定义的handler了,跟进这个resolve方法:

Spring中的可扩展点(一)自定义标签_apache_12

        可以看到红框对UserNameSpaceHandler进行了一个反射创建,然后蓝框里调用了UserNameSpaceHandler的init()方法,将UserBeanDefinitionParser注册到了UserNameSpaceHandler中,最后绿框将命名空间和对应的handler对应上。

Spring中的可扩展点(一)自定义标签_apache_13

        创建好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)
<init>:145, ClassPathXmlApplicationContext (org.springframework.context.support)
<init>:85, ClassPathXmlApplicationContext (org.springframework.context.support)
main:13, Application (com.zoo)


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  M5nxXzKbD3Q7   2023年11月12日   22   0   0 xmlmavenjar
  ehrZuhofWJiC   2024年04月26日   34   0   0 日志Java
yIqmAAsdee9S