• 11-Spring架构源码分析-IoC 之注册解析的 BeanDefinitions


    IoC 之注册解析的 BeanDefinitions

    DefaultBeanDefinitionDocumentReader 的 #processBeanDefinition() 方法,完成 Bean 标签解析的核心工作。代码如下:

    // DefaultBeanDefinitionDocumentReader.java
    
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        // 进行 bean 元素解析。
        // 如果解析成功,则返回 BeanDefinitionHolder 对象。而 BeanDefinitionHolder 为 name 和 alias 的 BeanDefinition 对象
        // 如果解析失败,则返回 null 。
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            // 进行自定义标签处理
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // 进行 BeanDefinition 的注册
                // Register the final decorated instance.
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // 发出响应事件,通知相关的监听器,已完成该 Bean 标签的解析。
            // Send registration event.
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 解析工作分为三步:
      • 1、解析默认标签。
      • 2、解析默认标签后下得自定义标签。
      • 3、注册解析后的 BeanDefinition 。
    • 经过前面两个步骤的解析,这时的 BeanDefinition 已经可以满足后续的使用要求了,那么接下来的工作就是将这些 BeanDefinition 进行注册,也就是完成第三步

    1. BeanDefinitionReaderUtils

    注册 BeanDefinition ,由 BeanDefinitionReaderUtils.registerBeanDefinition() 完成。代码如下:

    // BeanDefinitionReaderUtils.java
     
    public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {
    
        // 注册 beanName
        // Register bean definition under primary name.
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    
        // 注册 alias
        // Register aliases for bean name, if any.
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2. BeanDefinitionRegistry

    BeanDefinition 的注册,由接口 org.springframework.beans.factory.support.BeanDefinitionRegistry 定义。

    2.1 通过 beanName 注册

    调用 BeanDefinitionRegistry 的 #registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 方法,实现通过 beanName 注册 BeanDefinition 。代码如下:

    // DefaultListableBeanFactory.java
    
    /** Whether to allow re-registration of a different definition with the same name. */
    private boolean allowBeanDefinitionOverriding = true;
    
    /** Map of bean definition objects, keyed by bean name. */
    private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);
    /** List of bean definition names, in registration order. */
    private volatile List beanDefinitionNames = new ArrayList<>(256);
    /** List of names of manually registered singletons, in registration order. */
    private volatile Set manualSingletonNames = new LinkedHashSet<>(16);
    /** Cached array of bean definition names in case of frozen configuration. */
    @Nullable
    private volatile String[] frozenBeanDefinitionNames;
    
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
    
        // 校验 beanName 与 beanDefinition 非空
        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    
        // <1> 校验 BeanDefinition 。
        // 这是注册前的最后一次校验了,主要是对属性 methodOverrides 进行校验。
        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition) beanDefinition).validate();
            } catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }
    
        // <2> 从缓存中获取指定 beanName 的 BeanDefinition
        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        // <3> 如果已经存在
        if (existingDefinition != null) {
            // 如果存在但是不允许覆盖,抛出异常
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            // 覆盖 beanDefinition 大于 被覆盖的 beanDefinition 的 ROLE ,打印 info 日志
            } else if (existingDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (logger.isInfoEnabled()) {
                    logger.info("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            existingDefinition + "] with [" + beanDefinition + "]");
                }
            // 覆盖 beanDefinition 与 被覆盖的 beanDefinition 不相同,打印 debug 日志
            } else if (!beanDefinition.equals(existingDefinition)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            // 其它,打印 debug 日志
            } else {
                if (logger.isTraceEnabled()) {
                    logger.trace("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            // 允许覆盖,直接覆盖原有的 BeanDefinition 到 beanDefinitionMap 中。
            this.beanDefinitionMap.put(beanName, beanDefinition);
        // <4> 如果未存在
        } else {
            // 检测创建 Bean 阶段是否已经开启,如果开启了则需要对 beanDefinitionMap 进行并发控制
            if (hasBeanCreationStarted()) {
                // beanDefinitionMap 为全局变量,避免并发情况
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                synchronized (this.beanDefinitionMap) {
                    // 添加到 BeanDefinition 到 beanDefinitionMap 中。
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    // 添加 beanName 到 beanDefinitionNames 中
                    List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    // 从 manualSingletonNames 移除 beanName
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            } else {
                // Still in startup registration phase
                // 添加到 BeanDefinition 到 beanDefinitionMap 中。
                this.beanDefinitionMap.put(beanName, beanDefinition);
                // 添加 beanName 到 beanDefinitionNames 中
                this.beanDefinitionNames.add(beanName);
                // 从 manualSingletonNames 移除 beanName
                this.manualSingletonNames.remove(beanName);
            }
            
            this.frozenBeanDefinitionNames = null;
        }
    
        // <5> 重新设置 beanName 对应的缓存
        if (existingDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105

    处理过程如下:

    • <1> 对 BeanDefinition 进行校验,该校验也是注册过程中的最后一次校验了,主要是对 AbstractBeanDefinition 的 methodOverrides 属性进行校验。

    • <2> 根据 beanName 从缓存中获取 BeanDefinition 对象。

    • <3> 如果缓存中存在,则根据 allowBeanDefinitionOverriding 标志来判断是否允许覆盖。如果允许则直接覆盖。否则,抛出 BeanDefinitionStoreException 异常。

    • <4>若缓存中没有指定 beanName
      的 BeanDefinition,则判断当前阶段是否已经开始了 Bean 的创建阶段?如果是,则需要对 beanDefinitionMap 进行加锁控制并发问题,否则直接设置即可。

      • 对于 #hasBeanCreationStarted() 方法,后续做详细介绍,这里不过多阐述。
    • <5> 若缓存中存在该 beanName 或者单例 bean 集合中存在该 beanName ,则调用 #resetBeanDefinition(String beanName) 方法,重置 BeanDefinition 缓存。

    其实整段代码的核心就在于 this.beanDefinitionMap.put(beanName, beanDefinition); 代码块。而 BeanDefinition 的缓存也不是神奇的东西,就是定义一个 Map :

    • keybeanName
    • value 为 BeanDefinition 对象。
    2.2 注册 alias 和 beanName 的映射

    调用 BeanDefinitionRegistry 的 #registerAlias(String name, String alias) 方法,注册 aliasbeanName 的映射关系。代码如下:

    // SimpleAliasRegistry.java
    
    /** Map from alias to canonical name. */
    // key: alias
    // value: beanName
    private final Map aliasMap = new ConcurrentHashMap<>(16);
    
    @Override
    public void registerAlias(String name, String alias) {
        // 校验 name 、 alias
        Assert.hasText(name, "'name' must not be empty");
        Assert.hasText(alias, "'alias' must not be empty");
        synchronized (this.aliasMap) {
            // name == alias 则去掉alias
            if (alias.equals(name)) {
                this.aliasMap.remove(alias);
                if (logger.isDebugEnabled()) {
                    logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
                }
            } else {
                // 获取 alias 已注册的 beanName
                String registeredName = this.aliasMap.get(alias);
                // 已存在
                if (registeredName != null) {
                    // 相同,则 return ,无需重复注册
                    if (registeredName.equals(name)) {
                        // An existing alias - no need to re-register
                        return;
                    }
                    // 不允许覆盖,则抛出 IllegalStateException 异常
                    if (!allowAliasOverriding()) {
                        throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
                                name + "': It is already registered for name '" + registeredName + "'.");
                    }
                    if (logger.isDebugEnabled()) {
                        logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
                                registeredName + "' with new target name '" + name + "'");
                    }
                }
                // 校验,是否存在循环指向
                checkForAliasCircle(name, alias);
                // 注册 alias
                this.aliasMap.put(alias, name);
                if (logger.isTraceEnabled()) {
                    logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 注册 alias 和注册 BeanDefinition 的过程差不多。

    • 在最后,调用了 #checkForAliasCircle() 来对别名进行了循环检测。代码如下:

      protected void checkForAliasCircle(String name, String alias) {
          if (hasAlias(alias, name)) {
              throw new IllegalStateException("Cannot register alias '" + alias +
                      "' for name '" + name + "': Circular reference - '" +
                      name + "' is a direct or indirect alias for '" + alias + "' already");
          }
      }
      public boolean hasAlias(String name, String alias) {
          for (Map.Entry entry : this.aliasMap.entrySet()) {
              String registeredName = entry.getValue();
              if (registeredName.equals(name)) {
                  String registeredAlias = entry.getKey();
                  if (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias)) {
                      return true;
                  }
              }
          }
          return false;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19

      (a,b)
      (c,a)
      (b,c)

      • 如果 namealias 分别为 1 和 3 ,则构成 (1,3) 的映射。加入,此时集合中存在(A,1)(3,A) 的映射,意味着出现循环指向的情况,则抛出 IllegalStateException 异常。

    3. 小结

    到这里 BeanDefinition 基于 beanNamealias 的维度,都已经注入到缓存中,下一步则是等待初始化使用了。我们,后续的文章,继续搞起来。

  • 相关阅读:
    【Day_14 0510】▲幸运的袋子
    SPI通讯简介
    C++创建型模式-建造者模式
    Linux下载安装MySql
    idea如何关闭项目文件显示的浏览器图标
    化学试剂磷脂-聚乙二醇-羟基,DSPE-PEG-OH,DSPE-PEG-Hydroxyl,MW:5000
    Docker容器自启动
    绕过类安全问题分析方法
    Ubuntu调整swap大小
    Verilog 代码题练手 (2-2)
  • 原文地址:https://blog.csdn.net/xianghanscce/article/details/126358236