零. 阅读准备
读这篇文章前先看下预备知识:Spring 自定义标签
一. 代码阅读
自定义标签解析核心代码:
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); 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)); }
可以看出 Spring 代码逻辑很清晰:
- getNamespaceURI() 获取自定义标签的 namespace
- 而后使用 namespace 获取相应处理的 handler
- 最后由 handler 指定的 parser 来解析自定义的标签
(1) getNamespaceURI() 获取自定义标签的 namespace
public String getNamespaceURI(Node node) { return node.getNamespaceURI(); }
就是常规的 XML 内容提取
(2)而后使用 namespace 获取相应处理的 handler
debug 到这一步发现是使用了 NamespaceHandlerResolver 的实现类 DefaultNamespaceHandlerResolver 来获取对应的 handler
@Override public NamespaceHandler resolve(String namespaceUri) { // 获取所有配置在 spring.handlers 中的映射 Map<String, Object> handlerMappings = getHandlerMappings(); // 从映射关系中取出相应的value 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); return namespaceHandler; } catch (ClassNotFoundException ex) { throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "] not found", ex); } catch (LinkageError err) { throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]: problem with handler class file or dependent class", err); } } }
放入缓存后,我们可以看到缓存中已经有了我们为自定义标签新增的 handler:
(3)最后由 handler 指定的 parser 来解析自定义的标签
@Override public BeanDefinition parse(Element element, ParserContext parserContext) { return findParserForElement(element, parserContext).parse(element, parserContext); }
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) { // 获取 wenniuwuren:user 中的 user String localName = parserContext.getDelegate().getLocalName(element); // 根据 user 找到对应的 parser BeanDefinitionParser parser = this.parsers.get(localName); if (parser == null) { parserContext.getReaderContext().fatal( "Cannot locate BeanDefinitionParser for element [" + localName + "]", element); } return parser; }
@Override public final BeanDefinition parse(Element element, ParserContext parserContext) { // 使用自定义的 Parser 将 element 中的东西读取到 BeanDefinition 中 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; if (shouldParseNameAsAliases()) { String name = element.getAttribute(NAME_ATTRIBUTE); if (StringUtils.hasLength(name)) { aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name)); } } // 将 AbstractBeanDefinition 转换为 BeanDefinitionHolder BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases); // 注册 holder registerBeanDefinition(holder, parserContext.getRegistry()); if (shouldFireEvents()) { BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder); postProcessComponentDefinition(componentDefinition); parserContext.registerComponent(componentDefinition); } } catch (BeanDefinitionStoreException ex) { parserContext.getReaderContext().error(ex.getMessage(), element); return null; } } return definition; }
到此,自定义标签的数据就从配置文件加载到了内存,自定义标签的解析其实就是 Spring 提供给开发者的扩展使用,整体解析过程和 Spring 默认的标签类似。