Spring 自定义标签解析
- Author: HuiFer
- 源码阅读仓库: SourceHot-Spring
- 与自定义标签解析相关的类
org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParserorg.springframework.beans.factory.xml.NamespaceHandlerSupport
- 开始源码之前先搭建一个环境
环境搭建
- 创建对象
public class UserXtd {private String userName;private String emailAddress;public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getEmailAddress() {return emailAddress;}public void setEmailAddress(String emailAddress) {this.emailAddress = emailAddress;}}
- 创建 xsd 文件
<?xml version="1.0" encoding="UTF-8" ?><schema xmlns="http://www.w3.org/2001/XMLSchema"targetNamespace="http://www.huifer.com/schema/user"elementFormDefault="qualified"><element name="myUser"><complexType><attribute name="id" type="string"/><attribute name="userName" type="string"/><attribute name="emailAddress" type="string"/></complexType></element></schema>
- 创建 namespaceHandler
public class UserNamespaceHandler extends NamespaceHandlerSupport {@Overridepublic void init() {registerBeanDefinitionParser("myUser", new UserBeanDefinitionParser());}}
- 创建 beanDefinitionParser
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {/*** 标签对应class* @param element the {@code Element} that is being parsed* @return*/@Overrideprotected Class<?> getBeanClass(Element element) {return UserXtd.class;}@Overrideprotected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {// 获取 userName 标签属性值String name = element.getAttribute("userName");// 获取 emailAddress 标签属性值String address = element.getAttribute("emailAddress");if (StringUtils.hasText(name)) {builder.addPropertyValue("userName", name);}if (StringUtils.hasText(address)) {builder.addPropertyValue("emailAddress", address);}}}
- 创建 resource/META-INF/spring.handlers
http\://www.huifer.com/schema/user=com.huifer.source.spring.parser.UserNamespaceHandler
- 创建 resource/META-INF/spring.schemas
http\://www.huifer.com/schema/user.xsd=META-INF/spring-test.xsd
- 创建测试用例 xml
<?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:myname="http://www.huifer.com/schema/user"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.huifer.com/schema/user http://www.huifer.com/schema/user.xsd"><myname:myUser id="testUserBean" userName="huifer" emailAddress="huifer97@163.com"/></beans>
- 创建 Java 运行方法
/*** 自定义标签测试用例*/public class XSDDemo {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("XTD-xml.xml");UserXtd user = (UserXtd) applicationContext.getBean("testUserBean");System.out.println(user.getEmailAddress());}}
- 这里我们希望输出结果是
huifer97@163.com,运行后结果也确实是huifer97@163.com
解析 DefaultNamespaceHandlerResolver
- 入口方法
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {if (delegate.isDefaultNamespace(root)) {NodeList nl = root.getChildNodes();for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);if (node instanceof Element) {Element ele = (Element) node;if (delegate.isDefaultNamespace(ele)) {// 不同标签的解析parseDefaultElement(ele, delegate);}else {// 非spring 默认标签解析delegate.parseCustomElement(ele);}}}}else {delegate.parseCustomElement(root);}}
- 调用链路
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(org.w3c.dom.Element)org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)
/*** Parse a custom element (outside of the default namespace).* <p>* 自定义标签解析** @param ele the element to parse* @param containingBd the containing bean definition (if any)* @return the resulting bean definition*/@Nullablepublic BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {// 自定义标签解析String namespaceUri = getNamespaceURI(ele);if (namespaceUri == null) {return null;}// 根据命名空间获取处理类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));}

http://www.huifer.com/schema/user和我们定义的 xsd 文件中的 url 相同,如何找到对应的 NamespaceHandler,在META-INF/spring.handlers中有定义,http\://www.huifer.com/schema/user=com.huifer.source.spring.parser.UserNamespaceHandlerNamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);这行代码就是获取spring.handlers中的定义处理方法
org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver.resolve
/*** Locate the {@link NamespaceHandler} for the supplied namespace URI* from the configured mappings.** 根据 namespaceUri 获取对应的 {@link NamespaceHandler}* @param namespaceUri the relevant namespace URI* @return the located {@link NamespaceHandler}, or {@code null} if none found*/@Override@Nullablepublic NamespaceHandler resolve(String namespaceUri) {// 获取handlerMappingMap<String, Object> handlerMappings = getHandlerMappings();// 从 handlerMapping 中获取类名Object handlerOrClassName = handlerMappings.get(namespaceUri);if (handlerOrClassName == null) {return null;}// 判断是否处理过,处理过直接返回else if (handlerOrClassName instanceof NamespaceHandler) {return (NamespaceHandler) handlerOrClassName;}else {// 没有处理,进行反射还原类String className = (String) handlerOrClassName;try {// 通过反射还原类Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");}// 初始化类NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);// 调用init()方法,自定义类中实现namespaceHandler.init();// 放入缓存handlerMappings.put(namespaceUri, namespaceHandler);// 返回自定义的 namespaceHandlerreturn namespaceHandler;}catch (ClassNotFoundException ex) {throw new FatalBeanException("Could not find NamespaceHandler class [" + className +"] for namespace [" + namespaceUri + "]", ex);}catch (LinkageError err) {throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +className + "] for namespace [" + namespaceUri + "]", err);}}}
org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#getHandlerMappings跟踪这个方法
/*** Load the specified NamespaceHandler mappings lazily.** 获取handlerMappings*/private Map<String, Object> getHandlerMappings() {Map<String, Object> handlerMappings = this.handlerMappings;}

这里直接存在数据了,他是从什么时候加载的?
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#registerBeanDefinitions这个方法在注册 bean 定义的时候调用
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();int countBefore = getRegistry().getBeanDefinitionCount();// 注册方法// createReaderContext 初始化HandlerMappingdocumentReader.registerBeanDefinitions(doc, createReaderContext(resource));return getRegistry().getBeanDefinitionCount() - countBefore;}
继续跟踪
createReaderContextorg.springframework.beans.factory.xml.XmlBeanDefinitionReader#createReaderContext
public XmlReaderContext createReaderContext(Resource resource) {return new XmlReaderContext(resource, this.problemReporter, this.eventListener,this.sourceExtractor, this, getNamespaceHandlerResolver());}
继续跟踪
getNamespaceHandlerResolverorg.springframework.beans.factory.xml.XmlBeanDefinitionReader#getNamespaceHandlerResolverpublic NamespaceHandlerResolver getNamespaceHandlerResolver() {if (this.namespaceHandlerResolver == null) {this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();}return this.namespaceHandlerResolver;}
继续跟踪
createDefaultNamespaceHandlerResolverorg.springframework.beans.factory.xml.XmlBeanDefinitionReader#createDefaultNamespaceHandlerResolverprotected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {ClassLoader cl = (getResourceLoader() != null ? getResourceLoader().getClassLoader() : getBeanClassLoader());return new DefaultNamespaceHandlerResolver(cl);}
继续跟踪
DefaultNamespaceHandlerResolverorg.springframework.beans.factory.xml.DefaultNamespaceHandlerResolverpublic DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader) {this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);}
他回到了我们之前疑问的地方
handlerMappings如何出现的断点

public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader) {this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);}
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
此时还是空
走完

@Overridepublic String toString() {return "NamespaceHandlerResolver using mappings " + getHandlerMappings();}
/*** Load the specified NamespaceHandler mappings lazily.** 获取handlerMappings*/private Map<String, Object> getHandlerMappings() {Map<String, Object> handlerMappings = this.handlerMappings;// 缓存不存在if (handlerMappings == null) {synchronized (this) {handlerMappings = this.handlerMappings;if (handlerMappings == null) {if (logger.isTraceEnabled()) {logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");}try {// 将本地文件读出Properties mappings =PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);if (logger.isTraceEnabled()) {logger.trace("Loaded NamespaceHandler mappings: " + mappings);}handlerMappings = new ConcurrentHashMap<>(mappings.size());// 转换成map结构CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);this.handlerMappings = handlerMappings;}catch (IOException ex) {throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);}}}}return handlerMappings;}

org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#resolve
@Override@Nullablepublic NamespaceHandler resolve(String namespaceUri) {// 获取handlerMappingMap<String, Object> handlerMappings = getHandlerMappings();// 从 handlerMapping 中获取类名Object handlerOrClassName = handlerMappings.get(namespaceUri);if (handlerOrClassName == null) {return null;}// 判断是否处理过,处理过直接返回else if (handlerOrClassName instanceof NamespaceHandler) {return (NamespaceHandler) handlerOrClassName;}else {// 没有处理,进行反射还原类String className = (String) handlerOrClassName;try {// 通过反射还原类Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");}// 初始化类NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);// 调用init()方法,自定义类中实现namespaceHandler.init();// 放入缓存handlerMappings.put(namespaceUri, namespaceHandler);// 返回自定义的 namespaceHandlerreturn namespaceHandler;}catch (ClassNotFoundException ex) {throw new FatalBeanException("Could not find NamespaceHandler class [" + className +"] for namespace [" + namespaceUri + "]", ex);}catch (LinkageError err) {throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +className + "] for namespace [" + namespaceUri + "]", err);}}}
执行init方法
public class UserNamespaceHandler extends NamespaceHandlerSupport {@Overridepublic void init() {registerBeanDefinitionParser("myUser", new UserBeanDefinitionParser());}}
/*** Subclasses can call this to register the supplied {@link BeanDefinitionParser} to* handle the specified element. The element name is the local (non-namespace qualified)* name.** 将标签名称,标签解析类放入*/protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {this.parsers.put(elementName, parser);}
方法走完,回到开始的方法
/*** Parse a custom element (outside of the default namespace).* <p>* 自定义标签解析** @param ele the element to parse* @param containingBd the containing bean definition (if any)* @return the resulting bean definition*/@Nullablepublic BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {// 自定义标签解析String namespaceUri = getNamespaceURI(ele);if (namespaceUri == null) {return null;}// 根据命名空间获取处理类// org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver.resolveNamespaceHandler 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));}

org.springframework.beans.factory.xml.NamespaceHandler#parse
org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse@Override@Nullablepublic BeanDefinition parse(Element element, ParserContext parserContext) {BeanDefinitionParser parser = findParserForElement(element, parserContext);return (parser != null ? parser.parse(element, parserContext) : null);}
org.springframework.beans.factory.xml.NamespaceHandlerSupport#findParserForElement
@Nullableprivate BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {// 获取标签名称String localName = parserContext.getDelegate().getLocalName(element);// 在map中获取对应的标签解析类BeanDefinitionParser parser = this.parsers.get(localName);// 空报错if (parser == null) {parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element);}// 不为空返回return parser;}

org.springframework.beans.factory.xml.BeanDefinitionParser#parse
org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#parse
public final BeanDefinition parse(Element element, ParserContext parserContext) {/*** {@link AbstractSingleBeanDefinitionParser#parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)}*/AbstractBeanDefinition definition = parseInternal(element, parserContext);}
org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#parseInternal
@Overrideprotected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();String parentName = getParentName(element);if (parentName != null) {builder.getRawBeanDefinition().setParentName(parentName);}// 调用自己实现的方法 com.huifer.source.spring.parser.UserBeanDefinitionParser.getBeanClassClass<?> beanClass = getBeanClass(element);if (beanClass != null) {builder.getRawBeanDefinition().setBeanClass(beanClass);}else {// getBeanClassName 同样也是可以在自定义的解析类中实现String beanClassName = getBeanClassName(element);if (beanClassName != null) {builder.getRawBeanDefinition().setBeanClassName(beanClassName);}}builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));BeanDefinition containingBd = parserContext.getContainingBeanDefinition();if (containingBd != null) {// Inner bean definition must receive same scope as containing bean.// 设置scopebuilder.setScope(containingBd.getScope());}if (parserContext.isDefaultLazyInit()) {// Default-lazy-init applies to custom bean definitions as well.// 设置 lazy-initbuilder.setLazyInit(true);}// 执行解析方法,在自定义解析类中存在com.huifer.source.spring.parser.UserBeanDefinitionParser.doParsedoParse(element, parserContext, builder);return builder.getBeanDefinition();}

执行com.huifer.source.spring.parser.UserBeanDefinitionParser#doParse
@Overrideprotected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {// 获取 userName 标签属性值String name = element.getAttribute("userName");// 获取 emailAddress 标签属性值String address = element.getAttribute("emailAddress");if (StringUtils.hasText(name)) {builder.addPropertyValue("userName", name);}if (StringUtils.hasText(address)) {builder.addPropertyValue("emailAddress", address);}}
