IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring IoC Bean-生命周期源码梳理分享 -> 正文阅读

[Java知识库]Spring IoC Bean-生命周期源码梳理分享

Spring IoC Bean-生命周期

一、什么是Spring

1、Spring IoC

a.Dependency Injection(DI)–依赖注入

b.Dependency Lookup(DL)–依赖查找

c.Spring容器管理的对象包括什么

2、Spring AOP

二、Spring Bean 生命周期概览

1、概览图

a.Spring Bean的转换过程

下面这张图演示了一个可用的Spring Bean是如何从xml配置文件中演变过来的

ps:配置元信息来源不仅可以在xml中,也可以在properties文件里以及注解元信息。

从上面的图中,我们可以比较清楚的知道Bean的元信息经过解析得到BeanDefinition,然后通过InstantiationStrategy策略将Class实例化为相应的Bean实例,此时该Bean实例字段均为空,然后经过一系列操作将一个可用的Bean实例提供出来供我们使用,在我们使用完之后,容器销毁时,将这些资源进行释放,最终有JVM进行垃圾回收。

b.Spring Bean生命周期概览图

Spring内部IoC容器默认实现为:DefaultListableBeanFactory

Bean的生命周期与方法映射如下图所示:

Bean生命周期与方法映射

三、Spring Bean生命周期核心方法

1、registerBeanDefinition-Spring Bean注册

该方法定义于BeanDefinitionRegistry接口下,由DefaultListableBeanFactory提供具体实现,流程比较简单。

其实整个注册流程最核心的一段代码就是:this.beanDefinitionMap.put(beanName, beanDefinition);将相应的BeanDefinition注册到beanDefinitionMap中。key为baneName,value为BeanDefinition

// DefaultListableBeanFactory#registerBeanDefinition
/** Map of bean definition objects, keyed by bean name. */
// 存储beanName(key)与BeanDefinition(value)
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
// 存储beanName,实现容器BeanDefinition的顺序注册
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
/** Whether to allow re-registration of a different definition with the same name. */
// 是否允许相同名称不同BeanDefinition,后者覆盖前者
private boolean allowBeanDefinitionOverriding = true;
/** List of bean definition names, in registration order. */
//---------------------------------------------------------------------
// Implementation of BeanDefinitionRegistry interface
//---------------------------------------------------------------------
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {

   Assert.hasText(beanName, "Bean name must not be empty");
   Assert.notNull(beanDefinition, "BeanDefinition must not be null");

   if (beanDefinition instanceof AbstractBeanDefinition) {
      try {
         // <1> 对BeanDefinition的最后一次校验,主要对属性 methodOverrides 进行校验
         ((AbstractBeanDefinition) beanDefinition).validate();
      }
      catch (BeanDefinitionValidationException ex) {
         throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
               "Validation of bean definition failed", ex);
      }
   }
   // <2>从缓存中拿BeanDefinition
   BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
   // <2.1>如果缓存中有此BeanDefinition
   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 + "]");
         }
      }
      // 其它,打印 trace 日志(很低的一种日志级别,一般不使用)
      else {
         if (logger.isTraceEnabled()) {
            logger.trace("Overriding bean definition for bean '" + beanName +
                  "' with an equivalent definition: replacing [" + existingDefinition +
                  "] with [" + beanDefinition + "]");
         }
      }
     	// 进行BeanDefinition覆盖
      this.beanDefinitionMap.put(beanName, beanDefinition);
   }
   // <2.2>正常情况下,注册流程会走下面这个流程:
   else {
      // 检测Bean创建阶段已经开启,如果开启了就需要对BeanDefinitionMap进行并发控制(这里进行并发控制的原因我理解应该是:如果是Spring容器启动时是单线程的话,那么在注册阶段就不会出现Bean创建阶段的情况,既然出现了不同阶段同时进行的情况,那么一定是处于多线程的情况下,所以需要避免线程不安全的场景,所以需要加锁)
      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<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
            updatedDefinitions.addAll(this.beanDefinitionNames);
            updatedDefinitions.add(beanName);
            this.beanDefinitionNames = updatedDefinitions;
            // 从 manualSingletonNames 移除 beanName, manualSingletonNames用于存储registerBeanDefinition外的单例注册bean
            removeManualSingletonName(beanName);
         }
      }
      else {
         // Still in startup registration phase
         // 将BeanDefinition加入到beanDefinitionMap中
         this.beanDefinitionMap.put(beanName, beanDefinition);
         // 将beanName加入到beanDefinitionNames中
         this.beanDefinitionNames.add(beanName);
         // 从 manualSingletonNames 移除 beanName, manualSingletonNames用于存储registerBeanDefinition外的单例注册bean
         removeManualSingletonName(beanName);
      }
      this.frozenBeanDefinitionNames = null;
   }
   // 重新设置 beanName 对应的缓存
   if (existingDefinition != null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
   }
}

2、getMergedBeanDefinition-Spring Bean合并

该方法定义于ConfigurableBeanFactory接口下,由AbstractBeanFactory实现(考虑层次性容器)

此方法会返回一个BeanDefinition实例,如果当前Bean有parent指定,那么会返回一个父子合并后的BeanDefinition。

// AbstractBeanFactory#getMergedBeanDefinition
/*用来存储合并后的RootBeanDefinition缓存*/
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);
// 考虑层次性容器时会调用此方法(目前学习的过程当中还没有发现哪里有调用此方法)
@Override
public BeanDefinition getMergedBeanDefinition(String name) throws BeansException {
  //<1> 根据给定的name获得真正的beanName(有可能给定的name是别名)
  String beanName = transformedBeanName(name);
  // Efficiently check whether bean definition exists in this factory.
  //<2> 当前容器是否包含此BeanDefinition
  if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
    // <2.1> 如果当前容器没有,并且父容器实例是ConfigurableBeanFactory,那么就去到父容器中去递归查找
    return ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName);
  }
  // Resolve merged bean definition locally.
  // <3> 获取当前容器的BeanDefinition
  return getMergedLocalBeanDefinition(beanName);
}

// AbstractBeanFactory#getMergedLocalBeanDefinition
// 在spring执行doGetBean()方法时,调用的此方法 主要用于查找当前容器的BeanDefinition(不考虑层次性容器的场景)
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
  // Quick check on the concurrent map first, with minimal locking.
  // <1> 去到mergedBeanDefinitions中查找RootBeanDefinition信息
  RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
  // <2> 如果找到了,并且当前mbd不允许重新合并时,直接返回(stale字段的含义就是决定BeanDefinition是否重新合并)
  if (mbd != null && !mbd.stale) {
    return mbd;
  }
  // <3> 重载方法,获取当前容器下父子Bean合并后的BeanDefinition
  return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}

// AbstractBeanFactory#getMergedBeanDefinition
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
  throws BeanDefinitionStoreException {
	// <1> 重载方法(处理BeanDefinition合并的核心方法)
  return getMergedBeanDefinition(beanName, bd, null);
}

// AbstractBeanFactory#getMergedBeanDefinition
protected RootBeanDefinition getMergedBeanDefinition(
  String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
  throws BeanDefinitionStoreException {

  synchronized (this.mergedBeanDefinitions) {
    RootBeanDefinition mbd = null;
    RootBeanDefinition previous = null;

    // Check with full lock now in order to enforce the same merged instance.
    if (containingBd == null) {
      mbd = this.mergedBeanDefinitions.get(beanName);
    }

    if (mbd == null || mbd.stale) {
      previous = mbd;
      if (bd.getParentName() == null) {
        // Use copy of given root bean definition.
        if (bd instanceof RootBeanDefinition) {
          mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
        }
        else {
          mbd = new RootBeanDefinition(bd);
        }
      }
      else {
        // Child bean definition: needs to be merged with parent.
        BeanDefinition pbd;
        try {
          String parentBeanName = transformedBeanName(bd.getParentName());
          if (!beanName.equals(parentBeanName)) {
            pbd = getMergedBeanDefinition(parentBeanName);
          }
          else {
            BeanFactory parent = getParentBeanFactory();
            if (parent instanceof ConfigurableBeanFactory) {
              pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
            }
            else {
              throw new NoSuchBeanDefinitionException(parentBeanName,
                                                      "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
                                                      "': cannot be resolved without an AbstractBeanFactory parent");
            }
          }
        }
        catch (NoSuchBeanDefinitionException ex) {
          throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                                                 "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
        }
        // Deep copy with overridden values.
        mbd = new RootBeanDefinition(pbd);
        mbd.overrideFrom(bd);
      }

      // Set default singleton scope, if not configured before.
      if (!StringUtils.hasLength(mbd.getScope())) {
        mbd.setScope(SCOPE_SINGLETON);
      }

      // A bean contained in a non-singleton bean cannot be a singleton itself.
      // Let's correct this on the fly here, since this might be the result of
      // parent-child merging for the outer bean, in which case the original inner bean
      // definition will not have inherited the merged outer bean's singleton status.
      if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
        mbd.setScope(containingBd.getScope());
      }

      // Cache the merged bean definition for the time being
      // (it might still get re-merged later on in order to pick up metadata changes)
      if (containingBd == null && isCacheBeanMetadata()) {
        this.mergedBeanDefinitions.put(beanName, mbd);
      }
    }
    if (previous != null) {
      copyRelevantMergedBeanDefinitionCaches(previous, mbd);
    }
    return mbd;
  }
}

3、resolveBeforeInstantiation

4、createBeanInstance

5、populateBean

6、initializeBean

7、preInstantiateSingletons

8、destroyBean

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-10 11:43:27  更:2022-05-10 11:45:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:14:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码