在探究自定义标签的解析过程前,温顾一下使用会更方便解析过程的理解。
定义XSD文件
<?xml version="1.0"?>
XSD 如何定义可以看w3c中XML Schema中的教程
定义实体类
public class User{ private String id; private String userName; private String email; // 省略 set/get 方法 }
/** * 自定义标签的解析器 */ public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { @Override protected Class<?> getBeanClass(Element element) { return User.class; } /** * 用来解析自定义的标签 */ @Override protected void doParse(Element element, BeanDefinitionBuilder bean) { // 获取自定义标签属性 String userName = element.getAttribute("userName"); String email = element.getAttribute("email"); bean.addPropertyValue("userName",userName); bean.addPropertyValue("email",email); } }
import org.springframework.beans.factory.xml.NamespaceHandlerSupport; public class CustomNamespaceHandlerSupport extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("user", new UserBeanDefinitionParser()); } }
配置此代码后,当遇到自定义标签user:xxxx,user开头的自定义标签的元素时,就会使用UserBeanDefinitionParser解析器解析。
默认在META-INF文件夹下配置
Spring.handlers
http://www.w3school.com.cn/schema/user=com.yxx.CustomNamespaceHandlerSupport
Spring.schemes
http://www.w3school.com.cn/schema/user.xsd=META-INF/Spring-test.xsd
配置此信息可以让Spring找到xsd文件以及自定义NamespaceHandlerSupport
回到在默认标签解析时候的方法
DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { // 对beans 处理 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) { // 对 bean处理 Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { // 处理 默认的 http //w ww.springframework org/scherna beans parseDefaultElement(ele, delegate); } else { // 处理自定义的 比如 tx下的 delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
解析自定义标签
BeanDefinitionParserDelegate#parseCustomElement
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) { // 获取 命名空间 namespaceUri http://xxxxx.xsd // w3c提供的Node 提供了方法 String namespaceUri = getNamespaceURI(ele); if (namespaceUri == null) { return null; } // 提取自定义的标签处理器 // 通过命名空间获取对应的namespacehandler NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } // 使用自定自定义的 namespacehandler 进行解析 // 例如namespacehandler 可以解析全部的 myname 命名空间的 标签 // 命名空间处理器 namespacehandler 通过 不同的标签调用不同的 AbstractSingleBeanDefitionParser return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
此方法中首先获取此ele的命名空间,并通过命名空间处理程序解析器(DefaultNamespaceHandlerResolver)根绝命名空间名称获取命名空间处理器(NamespaceHandler),然后通过parse方法处理自定义标签(实际上此方法执行的就是UserBeanDefinitionParser#doParse)。
DefaultNamespaceHandlerResolver#resolve
public NamespaceHandler resolve(String namespaceUri) { // 获取handler mapper -----> 其实就是Spring.handlers 中配置的namespace-handler MaphandlerMappings = getHandlerMappings(); // 查看此namespace是否存在对应的handler Object handlerOrClassName = handlerMappings.get(namespaceUri); // 不存在 if (handlerOrClassName == null) { return null; } // 如果存在缓存 直接返回 else if (handlerOrClassName instanceof NamespaceHandler) { return (NamespaceHandler) handlerOrClassName; } else { // 存的是className String className = (String) handlerOrClassName; try { // 获取对应的classname 的Class对象 Class<?> handlerClass = ClassUtils.forName(className, this.classLoader); // 判断此Class 是否 集成实现 NamespaceHandler if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) { throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface"); } // 实例化 namespacehandler 并类型转换 NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass); // 初始化 // 将AbstractSingleBeanDefitionParser实例化并 注册到BeanDefnitionParser缓存中, registerBeanDefnitionParser namespaceHandler.init(); // 将namespacehandler添加到缓存 handlerMappings.put(namespaceUri, namespaceHandler); return namespaceHandler; } ... } }
handlerMappings此Map缓存中存放的为namespace-handler的映射,但是这个handler可能是已经实例化的NamespaceHandler,也可能是handlerClassName,如果是handlerClassName,需要先实例化再添加到缓存
NamespaceHandlerSupport#parse
public BeanDefinition parse(Element element, ParserContext parserContext) { // 查找 parserContext 对应的 的解析器 BeanDefinitionParser parser = findParserForElement(element, parserContext); // parser不为空 就解析标签, 并将beanDefinition注册到Spring容器中 return (parser != null ? parser.parse(element, parserContext) : null); }
将任务分解,首先查找出该ele解析的BeanDefinitionParser,然后进行解析,最后会执行UserBeanDefinitionParser#doParse。
NamespaceHandlerSupport#findParserForElement
@Nullable private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) { // 获取中的user String localName = parserContext.getDelegate().getLocalName(element); // registerBeanDefinitionParser (”user ”, new UserBeanDefinitionParser ()) ; 这里已经将 user --解析器保存在了 map中 // 获取user对应的解析器 BeanDefinitionParser parser = this.parsers.get(localName); if (parser == null) { parserContext.getReaderContext().fatal( "Cannot locate BeanDefinitionParser for element [" + localName + "]", element); } return parser; }
解析完成
AbstractBeanDefinitionParser#parse
public final BeanDefinition parse(Element element, ParserContext parserContext) { // 解析自定义标签除去默认属性的其他属性以及子标签 AbstractBeanDefinition definition = parseInternal(element, parserContext); if (definition != null && !parserContext.isNested()) { try { String id = resolveId(element, definition, parserContext); if (!StringUtils.hasText(id)) { parserContext.getReaderContext().error( "Id is required for element '" + parserContext.getDelegate().getLocalName(element) + "' when used as a top-level tag", element); } String[] aliases = null; // 解析 name 分割成别名 if (shouldParseNameAsAliases()) { String name = element.getAttribute(NAME_ATTRIBUTE); if (StringUtils.hasLength(name)) { aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name)); } } // 构造BeanDefinitionHolder对象 BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases); // 注册beanDefinition registerBeanDefinition(holder, parserContext.getRegistry()); if (shouldFireEvents()) { BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder); postProcessComponentDefinition(componentDefinition); parserContext.registerComponent(componentDefinition); } } catch (BeanDefinitionStoreException ex) { String msg = ex.getMessage(); parserContext.getReaderContext().error((msg != null ? msg : ex.toString()), element); return null; } } return definition; }
AbstractSingleBeanDefinitionParser#parseInternal
@Override protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { // 创建 BeanDefinition 构造器 BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(); // getParentName 由子类去实现 获取父类名字 String parentName = getParentName(element); if (parentName != null) { builder.getRawBeanDefinition().setParentName(parentName); } // getBeanClass 由子类重写获取当前标签对应的类类型 返回Class Class<?> 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. builder.setScope(containingBd.getScope()); } if (parserContext.isDefaultLazyInit()) { // Default-lazy-init applies to custom bean definitions as well. builder.setLazyInit(true); } // 子类重写的 解析方法 doParse(element, parserContext, builder); return builder.getBeanDefinition(); }
此方法解析parent、beanClass以及继承父类的scope和是否懒加载,并最终调用doParse方法实现自定义标签的处理,doParse此方法就为UserBeanDefinitionParser#doParse
至此自定义标签的解析完毕
经历的过程:
通过命名空间获取自定义的标签处理器
通过element获取当前标签的解析器
处理默认属性 id、name以及name分割后的alias
集成父类的scope和是否懒加载
调用自定义处理标签的UserBeanDefinitionParser#doParse方法
构造BeanDefinitionHolder对象
注册BeanDefinition
---- ** Cover 《Spring 源码深度解析》**
文章来源:https://www.cnblogs.com/aismvy/p/15561182.html
联系客服