自定义标签的解析

这一篇主要说明自定义标签的解析流程,除了 bean、alias、import、beans之外的标签,都属于自定义标签的范围,自定义标签的解析需要命名空间配合,

  1. 获取对应的命名空间
  2. 根据命名空间获取对应的命名空间处理器 handler
  3. 通过对应的 handler 去找到对应的解析器
  4. 通过对应的解析器去对自定义标签进行解析。
  1. protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
  2. if (delegate.isDefaultNamespace(root)) {
  3. NodeList nl = root.getChildNodes();
  4. for (int i = 0; i < nl.getLength(); i++) {
  5. Node node = nl.item(i);
  6. if (node instanceof Element) {
  7. Element ele = (Element) node;
  8. if (delegate.isDefaultNamespace(ele)) {
  9. parseDefaultElement(ele, delegate);
  10. }
  11. else {
  12. delegate.parseCustomElement(ele);
  13. }
  14. }
  15. }
  16. }
  17. else {
  18. delegate.parseCustomElement(root);
  19. }
  20. }

parseCustomElement(ele, null)

获取对应的命名空间,根据命名空间找到对应的命名空间处理器 handler,通过对应的 handler 去找到对应的解析器,最后使用解析器对标签进行对应的解析

  1. public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
  2. // 获取对应的命名空间
  3. String namespaceUri = getNamespaceURI(ele);
  4. if (namespaceUri == null) {
  5. return null;
  6. }
  7. // 根据命名空间找到对应的NamespaceHandlerspring
  8. NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
  9. if (handler == null) {
  10. error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
  11. return null;
  12. }
  13. // 调用自定义的NamespaceHandler进行解析
  14. return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
  15. }

resolve

从命名空间中解析出对应的Handler,然后拿到对应的解析器对其进行解析。

getHandlerMappings() 中的数据来源于在 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)) 中 createReaderContext 配置的默认值,会去对应的位置直接加载对应的文件,在此时进行解析。

  1. public NamespaceHandler resolve(String namespaceUri) {
  2. // 获取所有已经配置好的handler映射
  3. Map<String, Object> handlerMappings = getHandlerMappings();
  4. // 根据命名空间找到对应的信息
  5. Object handlerOrClassName = handlerMappings.get(namespaceUri);
  6. if (handlerOrClassName == null) {
  7. return null;
  8. }
  9. else if (handlerOrClassName instanceof NamespaceHandler) {
  10. // 如果已经做过解析,直接从缓存中读取
  11. return (NamespaceHandler) handlerOrClassName;
  12. }
  13. else {
  14. // 没有做过解析,则返回的是类路径
  15. String className = (String) handlerOrClassName;
  16. try {
  17. // 通过反射将类路径转化为类
  18. Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
  19. if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
  20. throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
  21. "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
  22. }
  23. // 实例化类
  24. NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
  25. // 调用自定义的namespaceHandler的初始化方法
  26. namespaceHandler.init();
  27. // 讲结果记录在缓存中
  28. handlerMappings.put(namespaceUri, namespaceHandler);
  29. return namespaceHandler;
  30. }
  31. catch (ClassNotFoundException ex) {
  32. throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
  33. "] for namespace [" + namespaceUri + "]", ex);
  34. }
  35. catch (LinkageError err) {
  36. throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
  37. className + "] for namespace [" + namespaceUri + "]", err);
  38. }
  39. }
  40. }
  1. public BeanDefinition parse(Element element, ParserContext parserContext) {
  2. // 获取元素的解析器
  3. BeanDefinitionParser parser = findParserForElement(element, parserContext);
  4. return (parser != null ? parser.parse(element, parserContext) : null);
  5. }

BeanDefinitionParser#parse

不同的标签有不同的处理类,具体的处理逻辑不尽相同,最终都会将其解析为 BeanDefinition 子类对象,将其注入到 beandefinitionMap 和 beanDefinitionNames 集合中去。

AnnotationConfigUtils.registerAnnotationConfigProcessors

在某些步骤会注入一些实现 BeanFactoryPostProcessor 接口的子类,后续在解析一些注解的时候会使用到。

  1. public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
  2. BeanDefinitionRegistry registry, @Nullable Object source) {
  3. // 获取beanFactory
  4. DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
  5. if (beanFactory != null) {
  6. if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
  7. // //设置依赖比较器
  8. beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
  9. }
  10. if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
  11. // //设置自动装配解析器
  12. beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
  13. }
  14. }
  15. // 创建BeanDefinitionHolder集合
  16. Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
  17. // 注册内部管理的用于处理@configuration注解的后置处理器的bean
  18. if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
  19. RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
  20. def.setSource(source);
  21. // 注册BeanDefinition到注册表中
  22. beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
  23. }
  24. // 注册内部管理的用于处理@Autowired,@Value,@Inject以及@Lookup注解的后置处理器bean
  25. if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
  26. RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
  27. def.setSource(source);
  28. beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
  29. }
  30. // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
  31. // 注册内部管理的用于处理JSR-250注解,例如@Resource,@PostConstruct,@PreDestroy的后置处理器bean
  32. if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
  33. RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
  34. def.setSource(source);
  35. beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
  36. }
  37. // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
  38. // 注册内部管理的用于处理JPA注解的后置处理器bean
  39. if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
  40. RootBeanDefinition def = new RootBeanDefinition();
  41. try {
  42. def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
  43. AnnotationConfigUtils.class.getClassLoader()));
  44. }
  45. catch (ClassNotFoundException ex) {
  46. throw new IllegalStateException(
  47. "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
  48. }
  49. def.setSource(source);
  50. beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
  51. }
  52. // 注册内部管理的用于处理@EventListener注解的后置处理器的bean
  53. if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
  54. RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
  55. def.setSource(source);
  56. beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
  57. }
  58. // 注册内部管理用于生产ApplicationListener对象的EventListenerFactory对象
  59. if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
  60. RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
  61. def.setSource(source);
  62. beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
  63. }
  64. return beanDefs;
  65. }

04-Spring自定义标签解析的更多相关文章

  1. Spring自定义标签解析与实现

           在Spring Bean注册解析(一)和Spring Bean注册解析(二)中我们讲到,Spring在解析xml文件中的标签的时候会区分当前的标签是四种基本标签(import.alias ...

  2. Spring 自定义标签配置

    前景:经常使用一些依赖于Spring的组件时,发现可以通过自定义配置Spring的标签来实现插件的注入,例如数据库源的配置,Mybatis的配置等.那么这些Spring标签是如何自定义配置的?学习Sp ...

  3. spring源码深度解析— IOC 之 自定义标签解析

    概述 之前我们已经介绍了spring中默认标签的解析,解析来我们将分析自定义标签的解析,我们先回顾下自定义标签解析所使用的方法,如下图所示: 我们看到自定义标签的解析是通过BeanDefinition ...

  4. 这一次搞懂Spring自定义标签以及注解解析原理

    前言 在上一篇文章中分析了Spring是如何解析默认标签的,并封装为BeanDefinition注册到缓存中,这一篇就来看看对于像context这种自定义标签是如何解析的.同时我们常用的注解如:@Se ...

  5. 自己构建一个Spring自定义标签以及原理讲解

    平时不论是在Spring配置文件中引入其他中间件(比如dubbo),还是使用切面时,都会用到自定义标签.那么配置文件中的自定义标签是如何发挥作用的,或者说程序是如何通过你添加的自定义标签实现相应的功能 ...

  6. spring基础---->spring自定义标签(一)

    Spring具有一个基于架构的扩展机制,可以使用xml文件定义和配置bean.本博客将介绍如何编写自定义XML bean的解析器,并用实例来加以说明.其实我一直相信 等你出现的时候我就知道是你. Sp ...

  7. spring自定义标签之 自我实现

     引言: 最近心情比较难以平静,周末的两天就跑出去散心了,西湖边上走走,看日落,还是不错的.回来博客上发现,在自定义标签上,最后一步实现忘记加上了.其实,人生的路程中,我们总是实现着自我的价值,让自己 ...

  8. Spring自定义标签的实现

    首先 简单写下 spring xml解析的过程 通过一段简单的 调用spring代码开始 public static void main(String[] args) { ApplicationCon ...

  9. angularjs directive (自定义标签解析)

    angularjs directive (自定义标签解析) 定义tpl <!-- 注意要有根标签 --> <div class="list list-inset" ...

  10. spring自定义标签之 规范定义XSD

    引言: spring的配置文件中,一切的标签都是spring定义好的.<bean/>等等,有了定义的规范,才能让用户填写的正常可用.想写自定义标签,但首先需要了解XML Schema De ...

随机推荐

  1. k8s-2-集成apollo配置中心

    主题: 在k8s中集成Apollo配置中心 架构图 一.配置中心概述 配置的几种方式 本课讲得是基于配置中心数据库实现 配置管理的现状 常见的配置中心 主讲:k8s configmap,apollo ...

  2. Shell 编程练习

    将后缀名为 .txt 的文件改成 .log [root@k8s-master test]# touch localhost_2020-01-{02..26}.txt [root@k8s-master ...

  3. GO - 高级编程

    https://books.studygolang.com/gopl-zh/ https://chai2010.cn/advanced-go-programming-book/

  4. HDU - 4725 The Shortest Path in Nya Graph 【拆点 + dijkstra】

    This is a very easy problem, your task is just calculate el camino mas corto en un grafico, and just ...

  5. Leetcode(83)-删除排序链表中的重复元素

    给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次. 示例 1: 输入: 1->1->2 输出: 1->2 示例 2: 输入: 1->1->2->3-&g ...

  6. 关于FFT的一些理解,以及如何手工计算FFT加深理解和验证正确性

    总结缺少逻辑性和系统性,主要便于自己理解和记忆 关于一维FFT的 于是复系数Cn是图像傅里叶变换的yn列向量 于是我们看到最后引入,Cn这个复系数的模来表征频率波的振幅记为Sn(即简谐波叠加的数量 然 ...

  7. Chinese Parents Game

    Chinese Parents Game <中国式家长>是一款模拟养成游戏. 玩家在游戏中扮演一位出生在普通的中式家庭的孩子. https://en.wikipedia.org/wiki/ ...

  8. CI / CD in Action

    CI / CD in Action Continuous Integration (CI) & Continuous Delivery (CD) https://github.com/mark ...

  9. 「NGK每日快讯」2021.2.2日NGK公链第91期官方快讯!

  10. int和Integer的比较详解

    说明: int为基本类型,Integer为包装类型: 装箱: 基本类型---> 包装类型 int ---> Integer 底层源码: .intValue() 拆箱: 包装类型---> ...