SpringBean生命周期
郑重声明
本文章仅仅是研究 bean 在 BeanFactory 中的生命周期。并且都是我自己的理解,仅供参考!!!
若能指出疏漏之处,不胜感激
我们知道Web容器中的Servlet拥有明确的生命周期,Spring容器中的Bean也拥有相似的生命周期。Bean生命周期由多个阶段组成,在所经历的每个阶段都提供相应的保留接口以供我们人为的对 bean 进行干涉。
首先,
- 当调用 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;
}
}
-
调用 BeanNameAware 的 setName()方法
- 如果 Bean 实现了BeanNameAware接口则调用 setName 方法为 bean 设置名字
Interface BeanNameAware{
//在创建此 bean 的 bean 工厂中设置 bean 的名称。
//在填充普通 bean 属性之后但在初始化回调(例如InitializingBean.afterPropertiesSet()或自定义初始化方法)之前调用。
void setName(String name)
}
-
调用 BeanFactoryAware 的setFactory 方法
- 如果 bean 实现了 BeanFactoryAware 接口则调用 setBeanFactory 方法将BeanFactory 的实例设置到 Bean 中
interface BeanFactoryAware extends Aware{
setBeanFactory(BeanFactory factory )
}
-
如果 BeanFactory 装配了
BeanPostProcess
则调用postProcessBeafreInitialization
方法对 bean 进行初始化前的后置处理- 此方法非常重要,因为可以对 bean 做一些特殊的自定义处理,用户可以根据自己的需要返回自己想要的bean 实例。
- 此方法为容器对 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; }
-
如果 bean 实现了 InitializingBean 接口则调用
afterPropertiesSet
方法
interface InitializingBean {
/**
在设置所有 bean 属性并满足BeanFactoryAware 、
ApplicationContextAware等后由包含BeanFactory调用。
此方法允许 bean 实例在设置所有 bean 属性后执行其整体配置和最终初始化的验证。
*/
void afterPropertiesSet() throws Exception;
}
- 如果 bean 通过 init-method 属性定义了初始化方法,则执行这个方法
- BeanPostProcessor后处理器定义了两个方法:其一是postProcessBefore Initialization(),在第(4)步调用;其二是Object postProcessAfterInitialization(Object bean,String beanName),这个方法在此时调用,容器再次获得对Bean进行加工处理的机会。
- 如果bean 定义了属性为scope=”prototype“则属于原型 bean,生命周期将交由调用者负责,如果 scope=”signleton“则将 Bean 实例放入 Spring 的缓存池中(使用 map 存储)
- 如果 Bean 的作用域为 signleton 当容器关闭时,Spring 会对此 bean 进行后续的生命周期管理工作,比如调用 destory 方法,在此处可以编写释放资源记录 bean 操作日志记录等。
- 如果Bean 的作用域为 signleton 并且在 init-method 中指定了Bean 销毁方法,那么 Spring 将执行这个方法,对 Bean 进行销毁,释放资源
Bean的完整生命周期从Spring容器着手实例化Bean开始,直到最终销毁Bean。其中经过了许多关键点,每个关键点都涉及特定的方法调用,可以将这些方法大致划分为4类
- Bean身的方法:如调用
Bean
构造函数实例化Bean、调用Setter设置Bean的属性值及通过的init-method和destroy-method
所指定的方法。 - Bean级生命周期接口方法:如
BeanNameAware
、BeanFactoryAware
、InitializingBeanDisposableBean
,这些接口方法由Bean类直接实现。 - 容器级生命周期接口方法:在图4-11中带“★”的步骤是由
InstantiationAwareBean
PostProcessor
和BeanPostProcessor
这两个接口实现的,一般称它们的实现类为“后处理器”。后处理器接口一般不由Bean本身实现,它们独立于Bean,实现类以容器附加装置的形式注册到Spring容器中,并通过接口反射为Spring容器扫描识别。当Spring容器创建任何Bean的时候,这些后处理器都会发生作用,所以这些后处理器的影响是全局性的。当然,用户可以通过合理地编写后处理器,让其仅对感兴趣的Bean进行加工处理。 - 工厂后处理器接口方法:包括
AspectJWeavingEnabler
、CustomAutowireConfigurer
、ConfigurationClassPostProcessor
等方法。工厂后处理器也是容器级的,在应用上下文装配配置文件后立即调用。
Spring容器中是否可以注册多个后处理器呢?答案是肯定的。只要它们同时实现org.springframework.core.Ordered接口,容器将按特定的顺序依次调用这些后处理器。