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

目录

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




	
		
			
				
					
					
					
				
			
		
	

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中的可扩展点(一)自定义标签_第1张图片3.我们创建的几个文件是如何关联到一起的

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

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

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

Spring中的可扩展点(一)自定义标签_第2张图片

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

Spring中的可扩展点(一)自定义标签_第3张图片

Spring中的可扩展点(一)自定义标签_第4张图片

具体调用堆栈:

: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(): Spring中的可扩展点(一)自定义标签_第5张图片

具体调用堆栈:

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():

Spring中的可扩展点(一)自定义标签_第6张图片

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

Spring中的可扩展点(一)自定义标签_第7张图片Spring中的可扩展点(一)自定义标签_第8张图片

具体调用堆栈:

: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():

Spring中的可扩展点(一)自定义标签_第9张图片

具体堆栈:

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()方法:

Spring中的可扩展点(一)自定义标签_第10张图片

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

Spring中的可扩展点(一)自定义标签_第11张图片

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

Spring中的可扩展点(一)自定义标签_第12张图片
        可以看到红框对UserNameSpaceHandler进行了一个反射创建,然后蓝框里调用了UserNameSpaceHandler的init()方法,将UserBeanDefinitionParser注册到了UserNameSpaceHandler中,最后绿框将命名空间和对应的handler对应上。

Spring中的可扩展点(一)自定义标签_第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)
:145, ClassPathXmlApplicationContext (org.springframework.context.support)
:85, ClassPathXmlApplicationContext (org.springframework.context.support)
main:13, Application (com.zoo)

你可能感兴趣的:(Spring,spring,java,后端)