博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
3.9 spring-自定义标签解析
阅读量:5774 次
发布时间:2019-06-18

本文共 7438 字,大约阅读时间需要 24 分钟。

  到这里,我们已经完成了分析默认标签的解析与提取过程,或许设计的内容太多,我们忘了我们是冲哪个函数开始了的,

让我们再次回顾一下默认标签解析方法的起始方法.

 

入口如下:

1 /** 2      * Parse the elements at the root level in the document: "import", "alias", "bean". 3      *  4      * @param root the DOM root element of the document 5      */ 6     protected void parseBeanDefinitions(Element root, 7             BeanDefinitionParserDelegate delegate) { 8         // 对Bean的处理 9         if (delegate.isDefaultNamespace(root)) {10             NodeList nl = root.getChildNodes();11             for (int i = 0; i < nl.getLength(); i++) {12                 Node node = nl.item(i);13                 if (node instanceof Element) {14                     Element ele = (Element) node;15                     if (delegate.isDefaultNamespace(ele)) {16                         // 对Bean的处理,如果是默认17                         parseDefaultElement(ele, delegate);18                     }19                     else {20                         // 对Bean的处理,如果是自定义21                         delegate.parseCustomElement(ele);22                     }23                 }24             }25         }26         else {27             delegate.parseCustomElement(root);28         }29     }

解析方法如下:

1     private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { 2         // 对
节点, 调用importBeanDefinitionResource方法解析, 此方法中, 又回到第一步读取配置文件并解析. 如此递归循环. 3 if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { 4 importBeanDefinitionResource(ele); 5 } 6 // 对
节点, 调用processAliasRegistration进行别名解析 7 else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { 8 processAliasRegistration(ele); 9 }10 //
节点调用processBeanDefinition进行解析11 else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {12 processBeanDefinition(ele, delegate);13 }14 //
的处理15 else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {16 // recurse17 doRegisterBeanDefinitions(ele);18 }19 }

核心方法:

1 /** 2      * Process the given bean element, parsing the bean definition and registering it with 3      * the registry. 4      */ 5     protected void processBeanDefinition(Element ele, 6             BeanDefinitionParserDelegate delegate) { 7         // 委托BeanDefinition类的parseBeanDefinitionElement方法进行元素解析,返回Beandefinition 8         // 类型的实例bdHolder 经过这个方法之后, 9         // bdHolder实例已经包含了我们配置文件中的各种属性了,例如 : class,name,id,alias10         BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);11         if (bdHolder != null) {12             //当返回的bdHolder 不为空的情况下,若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析.13             bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);14             try {15                 // Register the final decorated instance.16                 // 解析完成之后,需要对解析后的bdHolder 进行注册,同样注册操作委托给了BeanDefinitionUtils 的 registerBeanDefinition17                 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,18                         getReaderContext().getRegistry());19             }20             catch (BeanDefinitionStoreException ex) {21                 getReaderContext().error(22                         "Failed to register bean definition with name '"23                                 + bdHolder.getBeanName() + "'", ele, ex);24             }25             // Send registration event.26             // 最后发出响应事件,通知相关的监听器,这个bean已经加载完了.27             getReaderContext().fireComponentRegistered(28                     new BeanComponentDefinition(bdHolder));29         }30     }

  之前,我们已经用了大量的时间分析了 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); 这句代码;;

接下来就是我们本章的重点:

  bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);   首先我们先了解这局话的作用,从语义上讲,这段的码的意识无非是: 如果有需要的话,就对BeanDefinition 进行装饰;那么这句话到底是什么意思呢? 其实代码适用于这样的一个场景:

  好了,废话不多讲,我们继续分析下这段代码的逻辑;

 

1 public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, 2             BeanDefinitionHolder definitionHolder) { 3         /* 4          * 这里将第三个函数设置为null, 那么第三个函数是做什么用的呢? 什么情况下不为空呢? 5          *  6          * 其实这第三个参数是父类bean,当对某个嵌套配置进行分析时,这里需要传递父类beanDefinition 7          * .分析源代码得知,这里传递的参数其实是为了使用父类的scope属性,以备子类若没有设置scope 时默认使用父类的属性,这里分析的是顶层配置,所以传null 8          * , 9          */10         return decorateBeanDefinitionIfRequired(ele, definitionHolder, null);11     }

 

  这里将第三个函数设置为null, 那么第三个函数是做什么用的呢? 什么情况下不为空呢?

其实这第三个参数是父类bean,当对某个嵌套配置进行分析时,这里需要传递父类beanDefinition .分析源代码得知,这里传递的参数其实是为了使用父类的scope属性,以备子类若没有设置scope 时默认使用父类的属性,这里分析的是顶层配置,所以传null , 将第三个null 是指为 Null 后进一步追踪;

代码如下:

 

1 public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, 2             BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) { 3  4         BeanDefinitionHolder finalDefinition = definitionHolder; 5  6         // Decorate based on custom attributes first. 7         // 遍历所有属性,看看是否有适用于修饰的属性 8         NamedNodeMap attributes = ele.getAttributes(); 9         for (int i = 0; i < attributes.getLength(); i++) {10             Node node = attributes.item(i);11             finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);12         }13 14         // Decorate based on custom nested elements.15         // 遍历所有属性,看看是否有适用于修饰的子元素16         NodeList children = ele.getChildNodes();17         for (int i = 0; i < children.getLength(); i++) {18             Node node = children.item(i);19             if (node.getNodeType() == Node.ELEMENT_NODE) {20                 finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);21             }22         }23         return finalDefinition;24     }

  上面的代码,我们可以看到该方法分别对元素的所有属性和节点进行了decorateIfRequired()方法的调用,我们继续跟踪代码

1     public BeanDefinitionHolder decorateIfRequired(Node node, 2             BeanDefinitionHolder originalDef, BeanDefinition containingBd) { 3         // 获取命名空间 4         String namespaceUri = getNamespaceURI(node); 5         // 对非默认标签进行修饰 6         if (!isDefaultNamespace(namespaceUri)) { 7             // 根据命名空间找到对应的处理器 8             NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve( 9                     namespaceUri);10             if (handler != null) {11                 // 进行修饰12                 return handler.decorate(node, originalDef, new ParserContext(13                         this.readerContext, this, containingBd));14             }15             else if (namespaceUri != null16                     && namespaceUri.startsWith("http://www.springframework.org/")) {17                 error("Unable to locate Spring NamespaceHandler for XML schema namespace ["18                         + namespaceUri + "]", node);19             }20             else {21                 // A custom namespace, not to be handled by Spring - maybe "xml:...".22                 if (logger.isDebugEnabled()) {23                     logger.debug("No Spring NamespaceHandler found for XML schema namespace ["24                             + namespaceUri + "]");25                 }26             }27         }28         return originalDef;29     }

  

  程序走到这里已经相当清楚了,首先获取属性或者元素的命名空间,以此来判断该元素或属性是否适用于自定义标签的解析条件,找出自定义类型对应的

NamespaceHandler 并进一步解析,   我们总结一下 decorateIfRequired 的作用,在 decorateIfRequired 中,我们可以看到对于程序默认的属性或元素是直接忽略过去的,因为在之前已经处理过了, 这里只对自定义标签感兴趣,在这个方法中实现了寻找自定义标签,并根据自定义标签寻找命名空间处理器,并进一步的解析;
 

转载地址:http://ghxux.baihongyu.com/

你可能感兴趣的文章
JS重载
查看>>
python2和python3同安装在Windows上,切换问题
查看>>
php加速工具xcache的安装与使用(基于LNMP环境)
查看>>
android超链接
查看>>
redhat tomcat
查看>>
统计数据库大小
查看>>
IO流的学习--文件夹下文件的复制
查看>>
第十六章:脚本化HTTP
查看>>
EXCEL表中如何让数值变成万元或亿元
查看>>
nginx在响应request header时候带下划线的需要开启的选项
查看>>
Linux下DHCP服务器配置
查看>>
AndroidStudio中导入SlidingMenu报错解决方案
查看>>
我的IDEA配置
查看>>
myeclipse显示行号
查看>>
编写高性能的java程序
查看>>
Spring 的配置详解
查看>>
linux已经不存在惊群现象
查看>>
上位机和底层逻辑的解耦
查看>>
关于微信二次分享 配置标题 描述 图片??
查看>>
springcloud使用zookeeper作为config的配置中心
查看>>