[置顶] Spring 源码解析 ---- 自定义标签
2016-11-15 20:21
555 查看
零. 阅读准备
读这篇文章前先看下预备知识:Spring 自定义标签
一. 代码阅读
自定义标签解析核心代码:
可以看出 Spring 代码逻辑很清晰:
getNamespaceURI() 获取自定义标签的 namespace
而后使用 namespace 获取相应处理的 handler
最后由 handler 指定的 parser 来解析自定义的标签
(1) getNamespaceURI() 获取自定义标签的 namespace
就是常规的 XML 内容提取
(2)而后使用 namespace 获取相应处理的 handler
debug 到这一步发现是使用了 NamespaceHandlerResolver 的实现类 DefaultNamespaceHandlerResolver 来获取对应的 handler
放入缓存后,我们可以看到缓存中已经有了我们为自定义标签新增的 handler:
(3)最后由 handler 指定的 parser 来解析自定义的标签
到此,自定义标签的数据就从配置文件加载到了内存,自定义标签的解析其实就是 Spring 提供给开发者的扩展使用,整体解析过程和 Spring 默认的标签类似。
读这篇文章前先看下预备知识: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 默认的标签类似。
相关文章推荐
- Spring源码解析-自定义标签的解析
- [置顶] Spring-Session实现Session共享实现原理以及源码解析
- Spring源码解析之二 ------ 自定义标签的解析和注册(IOC的第一步)
- Spring源码解析笔记3——自定义标签的解析
- Spring源码解析(五)——自定义标签解析
- [Spring3.x源码]IoC(二)解析XML建立上下文
- Spring源码解析(一) Spring事务控制之Hibernate
- Spring源码学习-含有通配符路径解析(上) 推荐
- Spring源码解析(一) Spring事务控制之Hibernate
- Spring对注解(Annotation)处理源码分析2——解析和注入注解配置的资源
- SpringAOP[4.源码解析总结(2)]
- spring对java线程池封装源码解析
- Spring源码解析(一) Spring事务控制之Hibernate
- Spring源码解析之-资源加载(1)
- spring源码解析博客链接
- spring源码解析
- Spring源码解析
- spring IOC源码之解析xml中各个元素的过程
- Spring源码分析-BeanDefinition加载、解析和注册
- Spring源码分析-配置文件的解析(二)