Spring bean的生命周期

什么是 Bean

In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application. Beans, and the dependencies among them, are reflected in the configuration metadata used by a container.

简而言之,bean 是由 Spring IoC 容器实例化、组装和管理的对象。

什么是 Spring Bean 的生命周期

对于普通的 Java 对象,当 new 的时候创建对象,然后该对象就能够使用了。一旦该对象不再被使用,则由 Java 自动进行垃圾回收。

而 Spring 中的对象是 bean,bean 和普通的 Java 对象没啥大的区别,只不过 Spring 不再自己去 new 对象了,而是由 IoC 容器去帮助我们实例化对象并且管理它,我们需要哪个对象,去问 IoC 容器要即可。IoC 其实就是解决对象之间的耦合问题,Spring Bean 的生命周期完全由容器控制。

Bean生命周期

⚠️这里我们说的 Spring Bean 的生命周期主要指的是 singleton bean,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期。

bean 的作用域

  • singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
  • prototype : 每次请求都会创建一个新的 bean 实例。
  • request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
  • session : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。
  • global-session: 全局 session 作用域,仅仅在基于 Portlet 的 web 应用中才有意义,Spring5 已经没有了。Portlet 是能够生成语义代码(例如:HTML)片段的小型 Java Web 插件。它们基于 portlet 容器,可以像 servlet 一样处理 HTTP 请求。但是,与 servlet 不同,每个 portlet 都有不同的会话

Spring Singleton Bean 的生命周期

  1. 实例化 Instantiation
  2. 属性赋值 Populate
  3. 初始化 Initialization
  4. 销毁 Destruction

实例化 -> 属性赋值 -> 初始化 -> 销毁

Bean实例化的时机也分为两种,BeanFactory管理的Bean是在使用到Bean的时候才会实例化Bean,ApplicantContext管理的Bean在容器初始化的时候就会完成Bean实例化。

“实例化”和“初始化”是两个完全不同的过程,千万不要搞混,实例化只是给 Bean 分配了内存空间,而初始化则是将程序的执行权,从系统级别转换到用户级别,并开始执行用户添加的业务代码。

Bean实例化前后,可以进行一些处理,但是如果从Bean实例化前算开始,那么就要追溯到容器的初始化、beanDefiinition的加载开始。

  1. 实例化:第 1 步,实例化一个 Bean 对象
  2. 属性赋值:第 2 步,为 Bean 设置相关属性和依赖
  3. 初始化:初始化的阶段的步骤比较多,5、6步是真正的初始化,第 3、4 步为在初始化前执行,第 7 步在初始化后执行,初始化完成之后,Bean就可以被使用了
  4. 销毁:第 8~10步,第8步其实也可以算到销毁阶段,但不是真正意义上的销毁,而是先在使用前注册了销毁的相关调用接口,为了后面第9、10步真正销毁 Bean 时再执行相应的方法

Spring Singleton Bean 的生命周期详解

doCreateBean

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
    }

    if (instanceWrapper == null) {
        // 实例化阶段
        instanceWrapper = this.createBeanInstance(beanName, mbd, args);
    }

    ...

    Object exposedObject = bean;

    try {
        // 属性赋值阶段
        this.populateBean(beanName, mbd, instanceWrapper);
        // 初始化阶段
        exposedObject = this.initializeBean(beanName, exposedObject, mbd);
    } catch (Throwable var18) {
        ...
    }

    ...
}

至于销毁,是在容器关闭时调用的,详见ConfigurableApplicationContext#close()

createBeanInstance

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		//首先确保bean 已经被解析过
		Class<?> beanClass = resolveBeanClass(mbd, beanName);
        // 如果beanClass 不是public 类型,那么就 抛出异常,提示   non-public access not allowed
		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}
        // 如果存在,就返回一个  callback回调函数,在 obtainFromSupplier 方法里面
        //调用对应的具体方法 ,并转换成 BeanWrapper 类型
		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
		   // 这里转换成 BeanWrapper  类型
			return obtainFromSupplier(instanceSupplier, beanName);
		}
        // 如果存在对应的工厂方法,那么就使用工厂方法进行初始化
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
		boolean resolved = false;
		boolean autowireNecessary = false;
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
			//一个类有多个构造函数,每个构造商数都有不同的参数,所以调用前前需要先根据参数锁定构 
            //边的数或对应的工厂方法 
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
				    // 设置 已经解析
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		//如果已经解析过则使用解析好的构造函数方法,不用再次锁定 
		if (resolved) {
		    // 构造函数参数都已经解析完
			if (autowireNecessary) {
			    // 使用构造函数自动注入
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
      			//使用其默认构造函数实例化给定的bean
				return instantiateBean(beanName, mbd);
			}
		}

		// Candidate constructors for autowiring?
		// 如果上面没有解析好对应的构造函数, 这里看看有没有指定构造函数
		/**
		  具体里面其实 是 SmartInstantiationAwareBeanPostProcessor , 这个类 继承了
		  InstantiationAwareBeanPostProcessor, 调用里面的determineCandidateConstructors 方法 
		  来确认有没有指定的构造函数
		*/
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			// 构造函数自动注入
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// 获取确定用于默认构造的首选构造函数(如果有)。 如有必要,构造函数参数将自动装配。
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
			return autowireConstructor(beanName, mbd, ctors, null);
		}

		// 默认使用无参构造函数
		return instantiateBean(beanName, mbd);
	}

populateBean

 protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    if (bw == null) {
       // 如果beanWrapper为空,说明bean实例为null,需要跳过property值的设置
       // 但是如果beanWrapper为空而且mbd.hasPropertyValues()为true,说明bean实例为null,bean定义中存在property值,需要抛出异常
       if (mbd.hasPropertyValues()) {
          throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
       }
       else {
          // Skip property population phase for null instance.
          return;
       }
    }
 ​
    // 如果Bean是记录类型,那么Spring将跳过属性填充阶段,因为记录类型的属性是不可变的,无法进行属性注入
    if (bw.getWrappedClass().isRecord()) {
       if (mbd.hasPropertyValues()) {
          throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Cannot apply property values to a record");
       }
       else {
          // Skip property population phase for records since they are immutable.
          return;
       }
    }
 ​
    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
    // state of the bean before properties are set. This can be used, for example,
    // to support styles of field injection.
    // 在设置属性之前,让任何InstantiationAwareBeanPostProcessors都有机会修改bean的状态。例如,这可以用于支持现场注入的样式。
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
       for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
          if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
             return;
          }
       }
    }
 ​
    // 属性填充值
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
 ​
    // 自动装配类型 byName byType
    int resolvedAutowireMode = mbd.getResolvedAutowireMode();
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
       // 根据pvs 封装属性值
       MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
       // Add property values based on autowire by name if applicable.
       if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
          // 添加属性值,根据byName
          autowireByName(beanName, mbd, bw, newPvs);
       }
       // Add property values based on autowire by type if applicable.
       if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
          // 添加属性值,根据byType
          autowireByType(beanName, mbd, bw, newPvs);
       }
       pvs = newPvs;
    }
    // 此工厂是否持有InstantiationAwareBeanPostProcessor后置处理器
    if (hasInstantiationAwareBeanPostProcessors()) {
       if (pvs == null) {
          pvs = mbd.getPropertyValues();
       }
       // 遍历后置处理器,如果返回非空的PropertyValues,将pvs更新为返回的PropertyValues
       for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
          PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
          if (pvsToUse == null) {
             return;
          }
          pvs = pvsToUse;
       }
    }
 ​
    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    if (needsDepCheck) {
       PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
       checkDependencies(beanName, mbd, filteredPds, pvs);
    }
 ​
    if (pvs != null) {
       // 将属性应用到 bean 中
       applyPropertyValues(beanName, mbd, bw, pvs);
    }
 }

initializeBean

如果bean实现了InitializingBean接口,那么initializeBean会调用bean的afterPropertiesSet方法。这个方法在bean的属性初始化后会被执行。

如果在配置文件中通过init-method或注解指定了初始化方法,那么initializeBean会调用这个方法。

 protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    //用于执行BeanNameAware、BeanClassLoaderAware和BeanFactoryAware等Aware回调方法
    invokeAwareMethods(beanName, bean);
 ​
    Object wrappedBean = bean;
    // 如果mbd不为空并且不是合成bean,则执行BeanPostProcessor的beforeInitialization方法
    // 这里明明是mbd == null,为什么要解释成不为空呢,下面会有解释
    if (mbd == null || !mbd.isSynthetic()) {
       wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }
 ​
    try {
       // 执行bean的初始化方法
       invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
       throw new BeanCreationException(
             (mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
    }
    // 如果bean定义不存在或者bean不是合成的,则调用applyBeanPostProcessorsAfterInitialization方法,对bean进行初始化后的后处理器。
    if (mbd == null || !mbd.isSynthetic()) {
       wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
 ​
    return wrappedBean;
 }

什么是循环依赖

循环依赖就是循环引用,就是两个或多个 bean 相互之间的持有对方,比如 TestA 引用 TestB,TestB 引用 TestC,TestC引用 TestA,则他们最终会形成一个闭环。

Spring 是如何解决循环依赖的

构造器循环依赖

  1. 表示通过构造器注入构成的循环依赖,此依赖是无法解决的,只能拋出 BeanCurcenlylCreationException 异常表示循环依赖
  2. 如在创建 TestA类时,构造器需要 TestB 类,那将去创建 TestB,在创建 TestB 类时又发现需要 TestC 类,则又去创建TestC,最终在创建 TestC 时发现又需要 TestA,从而形成一个环,没办法创建。
  3. Spring 容器将每一个正在创建的 bean 标识符放在一个当前创建 bean 池中,bean标识符在创建过程中将一直保持在这个池中,因此如果在创建 bean 过程中发现自己已经在当的创建bean 池里时,将抛出 BeanCurrentlyInCreationException 异常表示循环依赖;而对于创建完毕的bean 将从当前创建bean池中清除掉。

setter 循环依赖

表示通过 setter 注入方式构成的循环依赖。对于 setter 注人造成的依赖是通过 Spring 容器提前暴露刚完成构造器注入但未完成其他步骤(如 setter 注入)的bean来完成的,而且只能解决单例作用域的bean 循环依赖。通过提前暴露一个单例工厂方法,从而使其他 bean 能引用到该bean。

  1. Spring 容器创建单例 testA bean,首先根据无参构造器创建 bean,并暴露一个ObjectFactory用于返回一个提前暴露一个创建中的bean,并将testA 标识符放到当前创建bean 池,然后进行 setter 注入testB。
  2. Spring 容器创建单例 testB bean,首先根据无参构造器创建 bean,并暴露一个ObjectFactory用于返回一个提前暴露一个创建中的 bean,并将testB 标识符放到当前创建 bean池,然后进行 setter 注入testC。
  3. Spring 容器创建单例 testC bean,首先根据无参构造器创建 bean,并暴露一个ObjectFactory用于返回一个提前暴露一个创建中的 bean,并将testC 标识符放到当前创建 bean池,然后进行 setter 注入testA。进行注入testA 时由于提前暴露了ObjectFactory工厂,从而使用它返回提前暴露一个创建中的bean。
  4. 最后在依赖注入testB 和 testA,完成 setter 注入。
  5. 对于单例 bean 来说,可以通过 setAllowCircularRefernces(false)来禁用循环引用

三级缓存

第⼀级缓存:singletonObjects,⽤于保存实例化、注⼊、初始化完成的 bean 实例;
第⼆级缓存:earlySingletonObjects,⽤于保存实例化完成的 bean 实例;
第三级缓存:singletonFactories,⽤于保存 bean 创建⼯⼚,以便后⾯有机会创建代理对象。

/** Cache of singleton objects: bean name --> bean instance */
/** 一级缓存:用于存放完全初始化好的 bean **/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
 
/** Cache of early singleton objects: bean name --> bean instance */
/** 二级缓存:存放原始的 bean 对象(尚未填充属性),用于解决循环依赖 */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

/** Cache of singleton factories: bean name --> ObjectFactory */
/** 三级级缓存:存放 bean 工厂对象,用于解决循环依赖 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

getSingleton方法中三级缓存的使用

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  // Spring首先从singletonObjects(一级缓存)中尝试获取
  Object singletonObject = this.singletonObjects.get(beanName);
  // 若是获取不到而且对象在建立中,则尝试从earlySingletonObjects(二级缓存)中获取
  if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    synchronized (this.singletonObjects) {
        singletonObject = this.earlySingletonObjects.get(beanName);
        if (singletonObject == null && allowEarlyReference) {
          ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
          if (singletonFactory != null) {
            //若是仍是获取不到而且允许从singletonFactories经过getObject获取,则经过singletonFactory.getObject()(三级缓存)获取
              singletonObject = singletonFactory.getObject();
              //若是获取到了则将singletonObject放入到earlySingletonObjects,也就是将三级缓存提高到二级缓存中
              this.earlySingletonObjects.put(beanName, singletonObject);
              this.singletonFactories.remove(beanName);
          }
        }
    }
  }
  return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

三级缓存的使用过程如下

  1. Spring 会先从一级缓存 singletonObjects 中尝试获取 Bean。
  2. 若是获取不到,而且对象正在建立中,就会尝试从二级缓存 earlySingletonObjects 中获取 Bean。
  3. 若还是获取不到,且允许从三级缓存 singletonFactories 中经过 singletonFactory 的 getObject() 方法获取 Bean 对象,就会尝试从三级缓存 singletonFactories 中获取 Bean。
  4. 若是在三级缓存中获取到了 Bean,会将该 Bean 存放到二级缓存中。

为什么要三级缓存?

二级缓存也是可以解决循环依赖的。为什么 Spring 不选择二级缓存,而要额外多添加一层缓存,使用三级缓存呢?

如果 Spring 选择二级缓存来解决循环依赖的话,那么就意味着所有 Bean 都需要在实例化完成之后就立马为其创建代理,而 Spring 的设计原则是在 Bean 初始化完成之后才为其创建代理。

使用三级缓存而非二级缓存并不是因为只有三级缓存才能解决循环引用问题,其实二级缓存同样也能很好解决循环引用问题。使用三级而非二级缓存并非出于 IOC 的考虑,而是出于 AOP 的考虑,即若使用二级缓存,在 AOP 情形注入到其他 Bean的,不是最终的代理对象,而是原始对象。

一条小咸鱼