Spring自定义标签工作原理
2018-01-11 15:19
399 查看
Spring自定义标签操作见博客:Spring自定义标签操作
基础知识:
Spring默认会将xml中所有等标签解析为BeanDefinition的抽象,自定义标签的本质是扩展Spring自身的标签,使其从自定义标签转化为BeanDefinition的过程。
核心类:
XmlBeanDefinitionReader
1.Spring Bean 注册方法:
2.解析Spring XML标签元素
核心类: DefaultBeanDefinitionDocumentReader
分析:Spring将bean标签的元素委托给delegate对象处理,parseBeanDefinitions()方法将XML文件的解析转交给delegate处理
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 {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
分析:
parseDefaultElement(ele, delegate):解析Spring自带的标签:例如import/alias/bean/beans
parseCustomElement : 解析自定义标签
Spring标签具体解析核心类:BeanDefinitionParserDelegate
分析:
通过XML命名空间(http://www.zhiwei.com/schema/user)获取命名空间解析器:
获取流程:
通过DefaultNamespaceHandlerResolver解析META-INF/spring.handlers,获取XML命令空间对应的名称空间解析器:com.zhiwei.basic.tag.NamespaceHandler,
本质通过类权限限定名通过反射机制获取自定义名称空间解析器实例
this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
源码:
代码分析:
instantiateClass:反射机制实例化NamespaceHandler实例,然后按照自定义标签名和自定义标签解析器信息缓存到父类NamespaceHandlerSupport的parsers集合中,同时将XML名称空间及处理器存放在DefaultNamespaceHandlerResolver 的handlerMappings中,最终返回NamespaceHandler。
回到BeanDefinitionParserDelegate 的 parseCustomElement方法
代码分析
功能:之前只是获取NamespaceHandler,并进行相关的配置信息缓存空间,这行代码是最底层解析标签并注入到IOC容器的具体实现。
具体分析handler.parse方法:
这里本质调到Namespacehandler父类:NamespaceHandlerSupport方法
源码:
findParserForElement(element, parserContext) :从缓存中获取自定义标签解析器
parse(element, parserContext): 解析自定义标签,并注入IOC容器
具体parse方法分析:
源码:自定义解析器父类AbstractBeanDefinitionParser.parse()方法:
源码:
代码分析:
分析:生成自定标签对应的BeanDefinition抽象,主要是调用父类AbstractSingleBeanDefinitionParser的parseInternal方法,方法内部调用我们自定义标签解析器的doParse(element, parserContext, builder);方法,实现自定义标签的处理,支持自定义标签的解析过程已经结束。
自定义标签BeanDefinition注入IOC容器:
具体代码:
主要是通过parserContext内部的readerContext成员的getRegistry()方法获取IOC容器,然后进行实质的Bean注入。
基础知识:
Spring默认会将xml中所有等标签解析为BeanDefinition的抽象,自定义标签的本质是扩展Spring自身的标签,使其从自定义标签转化为BeanDefinition的过程。
核心类:
XmlBeanDefinitionReader
1.Spring Bean 注册方法:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
2.解析Spring XML标签元素
核心类: DefaultBeanDefinitionDocumentReader
protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isInfoEnabled()) { logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } preProcessXml(root); parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; }
分析:Spring将bean标签的元素委托给delegate对象处理,parseBeanDefinitions()方法将XML文件的解析转交给delegate处理
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 {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
分析:
parseDefaultElement(ele, delegate):解析Spring自带的标签:例如import/alias/bean/beans
parseCustomElement : 解析自定义标签
Spring标签具体解析核心类:BeanDefinitionParserDelegate
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)); }
分析:
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
通过XML命名空间(http://www.zhiwei.com/schema/user)获取命名空间解析器:
获取流程:
通过DefaultNamespaceHandlerResolver解析META-INF/spring.handlers,获取XML命令空间对应的名称空间解析器:com.zhiwei.basic.tag.NamespaceHandler,
本质通过类权限限定名通过反射机制获取自定义名称空间解析器实例
this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
源码:
@Override public NamespaceHandler resolve(String namespaceUri) { Map<String, Object> handlerMappings = getHandlerMappings(); 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); 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); } } }
代码分析:
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass); namespaceHandler.init(); handlerMappings.put(namespaceUri, namespaceHandler);
instantiateClass:反射机制实例化NamespaceHandler实例,然后按照自定义标签名和自定义标签解析器信息缓存到父类NamespaceHandlerSupport的parsers集合中,同时将XML名称空间及处理器存放在DefaultNamespaceHandlerResolver 的handlerMappings中,最终返回NamespaceHandler。
回到BeanDefinitionParserDelegate 的 parseCustomElement方法
代码分析
handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
功能:之前只是获取NamespaceHandler,并进行相关的配置信息缓存空间,这行代码是最底层解析标签并注入到IOC容器的具体实现。
具体分析handler.parse方法:
这里本质调到Namespacehandler父类:NamespaceHandlerSupport方法
源码:
return findParserForElement(element, parserContext).parse(element, parserContext);
findParserForElement(element, parserContext) :从缓存中获取自定义标签解析器
parse(element, parserContext): 解析自定义标签,并注入IOC容器
具体parse方法分析:
源码:自定义解析器父类AbstractBeanDefinitionParser.parse()方法:
源码:
@Override 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; if (shouldParseNameAsAliases()) { String name = element.getAttribute(NAME_ATTRIBUTE); if (StringUtils.hasLength(name)) { aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name)); } } BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases); 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; }
代码分析:
AbstractBeanDefinition definition = parseInternal(element, parserContext);
分析:生成自定标签对应的BeanDefinition抽象,主要是调用父类AbstractSingleBeanDefinitionParser的parseInternal方法,方法内部调用我们自定义标签解析器的doParse(element, parserContext, builder);方法,实现自定义标签的处理,支持自定义标签的解析过程已经结束。
自定义标签BeanDefinition注入IOC容器:
具体代码:
registerBeanDefinition(holder, parserContext.getRegistry());
主要是通过parserContext内部的readerContext成员的getRegistry()方法获取IOC容器,然后进行实质的Bean注入。
相关文章推荐
- Spring @Transactional工作原理
- Spring学习一之IOC工作原理 2
- Hibernate、Spring和Struts工作原理及使用理由
- Hibernate、Spring和Struts工作原理及使用理由
- SpringMvc 及 Spring 工作原理和作用
- Spring工作原理
- spring的工作原理
- spring 的工作原理(定义)
- Hibernate 、Spring 和Struts 工作原理及使用理由
- spring工作原理以及同原始java执行的对比
- Spring工作原理探秘
- spring web.xml中 监听器(Listener)的工作原理和代码演示
- Hibernate、 Spring和Struts工作原理及使用理由
- Spring工作原理及其作用 .
- spring自定义标签aop实现
- Spring工作原理
- Spring的自定义标签
- Spring工作原理
- Spring工作原理及其作用
- Spring自定义标签的实现