spring源码深度解析(笔记三)--自定义标签的解析
来源:互联网 发布:电视怎么弄成网络电视 编辑:程序博客网 时间:2024/05/12 17:20
扩展spring自定义标签配置大致需要以下几个步骤:
创建一个需要扩展的组件.
定义一个XSD文件描述组件的内容.
创建一个文件,实现BeanDefinitionParser接口,用来解析XSD文件中的定义和组件定义.
创建一个Handler文件,扩展自NamespaceHandlerdSupport,目的是将组件注册到Spring容器.
编写Spring.handlers、Spring.schemas文件.
在spring中自定义标签非常有用,事务标签tx就是自定义标签.
自定义标签的解析:
public class BeanDefinitionParserDelegate {public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {//获取对应的命名空间String namespaceUri = getNamespaceURI(ele);//根据命名空间找到对应的NamespaceHandlerNamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);if (handler == null) {error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);return null;}//调用自定义的NamespaceHandler进行解析return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));}
//获取标签的命名空间
public String getNamespaceURI(Node node) {return node.getNamespaceURI();}
//提取自定义标签处理器
public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver {public NamespaceHandler resolve(String namespaceUri) {//获取所有已经配置的handler映射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的初始化方法namespaceHandler.init();//记录在缓存handlerMappings.put(namespaceUri, namespaceHandler);return namespaceHandler;}
private Map<String, Object> getHandlerMappings() {if (this.handlerMappings == null) {synchronized (this) {if (this.handlerMappings == null) {try {Properties mappings =PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);if (logger.isDebugEnabled()) {logger.debug("Loaded NamespaceHandler mappings: " + mappings);}Map<String, Object> handlerMappings = new ConcurrentHashMap<>(mappings.size());CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);this.handlerMappings = handlerMappings;}catch (IOException ex) {throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);}}}}return this.handlerMappings;}getHandlerMappings的主要功能就是读取Spring.Handlers配置文件并将配置文件缓存在map中.
借助了工具类PropertiesLoaderUtils进行了对配置文件的读取.
//标签解析
handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
public abstract class NamespaceHandlerSupport implements NamespaceHandler {public BeanDefinition parse(Element element, ParserContext parserContext) {//寻找解析器并进行解析操作return findParserForElement(element, parserContext).parse(element, parserContext);}private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {//获取自定义元素名称String localName = parserContext.getDelegate().getLocalName(element);//根据自定义元素名称找到对应的解析器BeanDefinitionParser parser = this.parsers.get(localName);if (parser == null) {parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element);}return parser;}}
@Overridepublic 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));}}//将AbstractBeanDefinition包装成BeanDefinitionHolderBeanDefinitionHolder 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;}
在parseInternal函数中,做了一系列数据准备,包括对beanClass、scope、lazyInit等属性的准备,然后调用了自定义的doParse函数..
到此为止,spring将bean从配置文件加载到内存的过程已经结束了;接下来的任务便是如何使用这些bean,即bean的加载.
0 0
- spring源码深度解析(笔记三)--自定义标签的解析
- 《Spring源码深度解析》阅读笔记6-自定义标签的解析
- 《Spring源码深度解析》学习笔记——自定义标签的解析
- spring源码深度解析(笔记二)--默认标签的解析
- Spring源码解析-自定义标签的解析
- 《Spring源码深度解析》阅读笔记5-默认标签的解析之bean标签的解析及注册
- 《Spring源码深度解析》学习笔记——默认标签的解析
- Spring 源码解析 ---- 自定义标签
- Spring源码解析-自定义标签解析
- Spring源码深度解析 带标签
- Spring源码深度解析(三)Spring的结构组成
- Spring源码深度解析(三)Spring的结构组成
- Spring自定义标签的解析
- Spring源码阅读-- 解析自定义命名空间的标签
- Spring源码解析-默认标签的解析
- spring源码深度解析(笔记一)
- spring源码深度解析(笔记四)--bean的加载
- Spring源码深度解析
- 在区块链侧链上进行Dapp技术开发
- 放羊娃的未来
- ckeditor 超链接编辑中显示高级设置tab
- js小写转成大写金额
- 数据结构与算法(C语言版)__顺序查找
- spring源码深度解析(笔记三)--自定义标签的解析
- windows下curl的使用
- datatables插件导出excel【指定excel单元格格式,禁止用科学计数法显示】
- git 设置密码
- [LeetCode]234. Palindrome Linked List
- [Math] 矩阵求导规则
- clipboard 实现复制
- 调用记事本使用快捷键
- Java web项目从tomcat转为weblogic环境所遇到的问题