Bean生命周期
一、前言
Bean 是由 Spring IoC 容器实例化、组装和管理的对象。
对于普通的 Java 对象,当 new 的时候创建对象,然后该对象就能够使用了。一旦该对象不再被使用,则由 Java 自动进行垃圾回收。
而 Spring 中的对象是 bean,bean 和普通的 Java 对象没啥大的区别,只不过 Spring 不再自己去 new 对象了,而是由 IoC 容器去帮助我们实例化对象并且管理它,我们需要哪个对象,去问 IoC 容器要即可。IoC 其实就是解决对象之间的耦合问题,Spring Bean 的生命周期完全由容器控制。
二、Spring Bean 的生命周期
这里我们说的 Spring Bean 的生命周期主要指的是 singleton bean,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期。
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 都有不同的会话。
我们知道对于普通的 Java 对象来说,它们的生命周期就是:
实例化
该对象不再被使用时通过垃圾回收机制进行回收
而对于 Spring Bean 的生命周期来说:
实例化 Instantiation
属性赋值 Populate
初始化 Initialization
销毁 Destruction
实例化 -> 属性赋值 -> 初始化 -> 销毁
三、Spring Bean 的生命周期的扩展点
Spring Bean 的生命周期的扩展点超级多,这里不可能全部列出来,只说核心的扩展点。这也就是为什么 Spring 的扩展性很好的原因,开了很多的口子,尽可能让某个功能高内聚松耦合,用户需要哪个功能就用哪个,而不是直接来一个大而全的东西。
3.1 Bean 自身的方法
比如构造函数、getter/setter 以及 init-method 和 destory-method 所指定的方法等,也就对应着上文说的实例化 -> 属性赋值 -> 初始化 -> 销毁四个阶段。
3.2 容器级的方法(BeanPostProcessor 一系列接口)
主要是后处理器方法,比如下图的 InstantiationAwareBeanPostProcessor、BeanPostProcessor 接口方法。这些接口的实现类是独立于 Bean 的,并且会注册到 Spring 容器中。在 Spring 容器创建任何 Bean 的时候,这些后处理器都会发生作用。
3.3 Spring源码跟进
由于篇幅和时间原因,这里先不进行源码的整理,等有空再来自己整理一翻吧哈哈哈
源码根据参考:一文读懂Spring Bean生命周期-CSDN
四、总结
4.1 bean生命周期流程图
4.1.1 整体流程解释
BeanDefinition:
作用:定义了 Bean 的配置信息,包括类名、属性、构造方法参数等。
使用场景:在 Spring 配置文件或注解中定义 Bean 时,Spring 会将这些配置解析成 BeanDefinition 对象。
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation:
作用:在 Bean 实例化之前执行,可以返回一个代理对象来代替真实对象。
使用场景:用于 AOP 的场景,比如创建一个代理 Bean。
Bean 实例化:
作用:根据 BeanDefinition 创建 Bean 的实例。
使用场景:Spring 容器启动时,或者获取 Bean 时,如果 Bean 还未创建,则会触发实例化。
InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation:
作用:在 Bean 实例化之后,设置属性之前调用。
使用场景:可以在这个阶段进行自定义逻辑处理,比如字段的检查。
InstantiationAwareBeanPostProcessor#postProcessProperties:
作用:对 Bean 的属性进行处理。
使用场景:比如可以用于依赖注入中的属性填充。
Bean属性赋值:
作用:根据 BeanDefinition 中的配置为 Bean 的属性赋值。
使用场景:在 Bean 创建过程中自动注入配置的属性。
BeanNameAware#setBeanName:
作用:注入当前 Bean 的名称。
使用场景:当 Bean 需要知道自己在容器中的名字时使用。
BeanClassLoaderAware#setBeanClassLoader:
作用:注入 ClassLoader。
使用场景:当 Bean 需要访问 ClassLoader 时使用。
BeanFactoryAware#setBeanFactory:
作用:注入 BeanFactory。
使用场景:当 Bean 需要访问 Spring 容器时使用。
BeanPostProcessor#postProcessBeforeInitialization:
作用:在 Bean 初始化之前执行。
使用场景:可以用于自定义逻辑处理,比如检查是否所有必需的属性已设置。
InitializingBean#afterPropertiesSet:
作用:当所有 Bean 属性都已经设置好后执行。
使用场景:可以用于检查 Bean 的配置是否正确。
init-method属性配置的初始化方法:
作用:调用自定义的初始化方法。
使用场景:用于 Bean 需要执行自定义初始化逻辑时。
BeanPostProcessor#postProcessAfterInitialization:
作用:在 Bean 初始化之后执行。
使用场景:可以修改 Bean 或者返回一个包装过的 Bean,常用于 AOP。
4.2 常用接口说明
BeanNameAware
该接口只有一个方法 setBeanName(String name)
,用来获取 bean 的 id 或者 name。
BeanFactoryAware
该接口只有一个方法 setBeanFactory(BeanFactory beanFactory)
,用来获取当前环境中的 BeanFactory。
ApplicationContextAware
该接口只有一个方法 setApplicationContext(ApplicationContext applicationContext)
,用来获取当前环境中的 ApplicationContext。
InitializingBean
该接口只有一个方法 afterPropertiesSet()
,在属性注入完成后调用。
DisposableBean
该接口只有一个方法 destroy()
,在容器销毁的时候调用,在用户指定的 destroy-method 之前调用。
BeanPostProcessor
该接口有两个方法:
postProcessBeforeInitialization(Object bean, String beanName)
:在初始化之前调用此方法
postProcessAfterInitialization(Object bean, String beanName)
:在初始化之后调用此方法,当一个类被增强实现了AOP也是用到了该接口
通过方法签名我们可以知道,我们可以通过 beanName 来筛选出我们需要进行个性化定制的 bean。
InstantiationAwareBeanPostProcessor
该类是 BeanPostProcessor 的子接口,常用的有如下三个方法:
postProcessBeforeInstantiation(Class beanClass, String beanName)
:在bean实例化之前调用
postProcessProperties(PropertyValues pvs, Object bean, String beanName)
:在bean实例化之后、设置属性前调用
postProcessAfterInstantiation(Class beanClass, String beanName)
:在bean实例化之后调用
InitializingBean
对应生命周期的初始化阶段,在上面源码的 invokeInitMethods(beanName, wrappedBean, mbd);
方法中调用。
有一点需要注意,因为 Aware 方法都是执行在初始化方法之前,所以可以在初始化方法中放心大胆的使用 Aware 接口获取的资源,这也是我们自定义扩展 Spring 的常用方式。
除了实现 InitializingBean 接口之外还能通过注解或者 xml 配置的方式指定初始化方法,至于这几种定义方式的调用顺序其实没有必要记。因为这几个方法对应的都是同一个生命周期,只是实现方式不同,我们一般只采用其中一种方式。
DisposableBean
类似于 InitializingBean,对应生命周期的销毁阶段,以ConfigurableApplicationContext#close()
方法作为入口,实现是通过循环取所有实现了 DisposableBean 接口的 Bean 然后调用其 destroy() 方法,感兴趣的可以自行跟一下源码。
五、代码演示
思路:创建一个类 UserBean ,让其实现几个特殊的接口,并分别在接口实现的构造器、接口方法中断点,观察线程调用栈,分析出 Bean 对象创建和管理关键点的触发时机。
5.1 UserBean 类
@Component
public class UserBean implements InitializingBean, BeanNameAware, DisposableBean, ApplicationContextAware {
private int id;
private String name;
public UserBean(int id, String name) {
this.id = id;
this.name = name;
System.out.println("2. 调用构造函数");
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
System.out.println("5. 属性注入 id");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("5. 属性注入 name");
}
@Override
public void setBeanName(String name) {
System.out.println("6. 调用 BeanNameAware.setBeanName() 方法");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
UserBean userBean = (UserBean) applicationContext.getBean("userBean");
System.out.println(userBean);
System.out.println("7. 调用 BeanNameAware.setBeanName() 方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("9. 调用 InitializingBean.afterPropertiesSet() 方法");
}
public void myInit() {
System.out.println("10. 调用 init-method 方法");
}
@Override
public void destroy() throws Exception {
System.out.println("12. 调用 DisposableBean.destroy() 方法");
}
public void myDestroy() {
System.out.println("13. 调用 destroy-method 方法");
}
@Override
public String toString() {
return "UserBean{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
5.2 InstantiationAwareBeanPostProcessor 接口实现类
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if ("userBean".equals(beanName)) {
System.out.println("1. 调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 方法");
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if ("userBean".equals(beanName)) {
UserBean userBean = (UserBean) bean;
System.out.println("3. 调用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法");
System.out.println(userBean);
}
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if ("userBean".equals(beanName)) {
System.out.println("4. 调用 InstantiationAwareBeanPostProcessor.postProcessProperties() 方法");
}
return null;
}
}
5.3 BeanPostProcessor 接口实现类
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("userBean".equals(beanName)) {
System.out.println("8. 调用 BeanPostProcessor.postProcessBeforeInitialization() 方法");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
/*if ("userBean".equals(beanName)) {
System.out.println("11. 调用 BeanPostProcessor.postProcessAfterInitialization() 方法");
}*/
System.out.println("11. 调用 BeanPostProcessor.postProcessAfterInitialization() 方法");
//cglib代理对象
Enhancer enhancer = new Enhancer();
//设置需要增强的类
enhancer.setSuperclass(bean.getClass());
//执行回调方法,增强方法
enhancer.setCallback(new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
if (method.getName().equals("toString")) {
return "cglib代理对象";
}
return method.invoke(bean, objects);
}
});
//创建代理对象
return enhancer.create();
return bean;
}
}
5.4 BeanFactoryPostProcessor 接口实现类
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("0. 调用 BeanFactoryPostProcessor.postProcessBeanFactory() 方法");
}
}
5.5 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
">
<bean class="com.riemann.test.MyInstantiationAwareBeanPostProcessor" />
<bean id="userBean" class="com.riemann.test.UserBean" init-method="myInit" destroy-method="myDestroy">
<!-- 构造函数注入 -->
<constructor-arg index="0" type="int">
<value>1</value>
</constructor-arg>
<constructor-arg index="1" type="java.lang.String">
<value>略略略</value>
</constructor-arg>
<!-- setter方法注入 -->
<property name="id" value="2"/>
<property name="name" value="riemann"/>
</bean>
<bean class="com.riemann.test.MyBeanPostProcessor" />
<bean class="com.riemann.test.MyBeanFactoryPostProcessor" />
</beans>
5.6 测试类
public class BeanLifeCycleTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserBean user = (UserBean) applicationContext.getBean("userBean");
((AbstractApplicationContext) applicationContext).close();
}
}