自己理解的 SpringBean 生命周期

45 阅读5分钟

SpringBean生命周期

郑重声明

本文章仅仅是研究 bean 在 BeanFactory 中的生命周期。并且都是我自己的理解,仅供参考!!!
若能指出疏漏之处,不胜感激

我们知道Web容器中的Servlet拥有明确的生命周期,Spring容器中的Bean也拥有相似的生命周期。Bean生命周期由多个阶段组成,在所经历的每个阶段都提供相应的保留接口以供我们人为的对 bean 进行干涉。
首先,

  1. 当调用 getBean 的时候会调用 InstantiationAwareBeanPostProcessor # postProcessBeforeInstantiation()方法,调用 InstantiationAwareBeanPostProcessor #postProcessProperties方法。(Spring5.1 之前调用的是 postProcessPropertyValues方法)

package org.springframework.beans.factory.config;

import java.beans.PropertyDescriptor;

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.lang.Nullable;

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

//在 bean 实例化之前需要调用此BeanPostProcess返回目标 bean的代理
	@Nullable
	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

	default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		return true;
	}

	//在工厂给定的属性值之前对 bean 进行后处理。
	@Nullable
	default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
			throws BeansException {

		return null;
	}

//Spring5.1 版本中此方法已经废弃
	@Deprecated
	@Nullable
	default PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {

		return pvs;
	}

}
  1. 调用 BeanNameAware 的 setName()方法

    1. 如果 Bean 实现了BeanNameAware接口则调用 setName 方法为 bean 设置名字
Interface BeanNameAware{
//在创建此 bean 的 bean 工厂中设置 bean 的名称。
//在填充普通 bean 属性之后但在初始化回调(例如InitializingBean.afterPropertiesSet()或自定义初始化方法)之前调用。
	void setName(String name)
}
  1. 调用 BeanFactoryAware 的setFactory 方法

    1. 如果 bean 实现了 BeanFactoryAware 接口则调用 setBeanFactory 方法将BeanFactory 的实例设置到 Bean 中
interface BeanFactoryAware extends Aware{
	setBeanFactory(BeanFactory factory )
}
  1. 如果 BeanFactory 装配了BeanPostProcess 则调用postProcessBeafreInitialization方法对 bean 进行初始化前的后置处理

    1. 此方法非常重要,因为可以对 bean 做一些特殊的自定义处理,用户可以根据自己的需要返回自己想要的bean 实例。
    2. 此方法为容器对 bean 的后续处理提供了切入点。(AOP 就是基于BeanPostProcessor
    public interface BeanPostProcessor {
    
    /*
    在任何 bean 初始化回调(如 InitializingBean 的afterPropertiesSet或自定义 init 方法)
    之前将此BeanPostProcessor应用于给定的新 bean 实例
    在 bean 初始化之前可调用此 process 为 bean 设置新的属性。
    */
    	@Nullable
    	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		return bean;
    	}
    
    	/*
    	在任何 bean 初始化回调(如 InitializingBean 的afterPropertiesSet或自定义 init 方法)之后,
    将此BeanPostProcessor应用于给定的新 bean 实例。
    bean的后置处理器
    */	
    	@Nullable
    	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		return bean;
    	}
    
  2. 如果 bean 实现了 InitializingBean 接口则调用 afterPropertiesSet方法

interface InitializingBean {

	/**
	在设置所有 bean 属性并满足BeanFactoryAware 、 
	ApplicationContextAware等后由包含BeanFactory调用。 
	此方法允许 bean 实例在设置所有 bean 属性后执行其整体配置和最终初始化的验证。
		 */
	void afterPropertiesSet() throws Exception;

}
  1. 如果 bean 通过 init-method 属性定义了初始化方法,则执行这个方法
  2. BeanPostProcessor后处理器定义了两个方法:其一是postProcessBefore Initialization(),在第(4)步调用;其二是Object postProcessAfterInitialization(Object bean,String beanName),这个方法在此时调用,容器再次获得对Bean进行加工处理的机会。
  3. 如果bean 定义了属性为scope=”prototype“则属于原型 bean,生命周期将交由调用者负责,如果 scope=”signleton“则将 Bean 实例放入 Spring 的缓存池中(使用 map 存储)
  4. 如果 Bean 的作用域为 signleton 当容器关闭时,Spring 会对此 bean 进行后续的生命周期管理工作,比如调用 destory 方法,在此处可以编写释放资源记录 bean 操作日志记录等。
  5. 如果Bean 的作用域为 signleton 并且在 init-method 中指定了Bean 销毁方法,那么 Spring 将执行这个方法,对 Bean 进行销毁,释放资源

Bean的完整生命周期从Spring容器着手实例化Bean开始,直到最终销毁Bean。其中经过了许多关键点,每个关键点都涉及特定的方法调用,可以将这些方法大致划分为4类

  1. Bean身的方法:如调用Bean构造函数实例化Bean、调用Setter设置Bean的属性值及通过的init-method和destroy-method所指定的方法。
  2. Bean级生命周期接口方法:如BeanNameAwareBeanFactoryAwareInitializingBeanDisposableBean,这些接口方法由Bean类直接实现。
  3. 容器级生命周期接口方法:在图4-11中带“★”的步骤是由InstantiationAwareBean PostProcessorBeanPostProcessor这两个接口实现的,一般称它们的实现类为“后处理器”。后处理器接口一般不由Bean本身实现,它们独立于Bean,实现类以容器附加装置的形式注册到Spring容器中,并通过接口反射为Spring容器扫描识别。当Spring容器创建任何Bean的时候,这些后处理器都会发生作用,所以这些后处理器的影响是全局性的。当然,用户可以通过合理地编写后处理器,让其仅对感兴趣的Bean进行加工处理。
  4. 工厂后处理器接口方法:包括AspectJWeavingEnablerCustomAutowireConfigurerConfigurationClassPostProcessor等方法。工厂后处理器也是容器级的,在应用上下文装配配置文件后立即调用。

Spring容器中是否可以注册多个后处理器呢?答案是肯定的。只要它们同时实现org.springframework.core.Ordered接口,容器将按特定的顺序依次调用这些后处理器。