什么是 Bean 的生命周期
Spring 是一个管理 Bean 的容器,它负责对象的创建、对象之间关系的维护 / 依赖的维护、对象的销毁等。所谓 Bean 的生命周期就是:对象从创建到最终销毁的整个过程。其实我们研究生命周期主要研究的是:在哪个时间节点上调用了哪个方法。所以我们需要着重了解在这个生命线上都有哪些特殊的时间节点。了解了这些特殊的时间节点之后,我们才能确定代码该写在哪里,才能保证当生命线走到这个节点时,代码会被执行。
Bean 的生命周期之五步
Bean 的生命周期可以粗略的划分为五大步:
- 第一步:实例化 Bean
- 第二步:Bean 属性赋值
- 第三步:初始化 Bean
- 第四步:使用 Bean
- 第五步:销毁 Bean
编写测试程序:
/**
* 定义一个普通的 Java 类
*/
@Component
public class User {
private String name;
public User() {
System.out.println("1.实例化bean");
}
@Value("张三")
public void setName(String name) {
this.name = name;
System.out.println("2.bean属性赋值");
}
@PostConstruct
public void initBean() {
System.out.println("3.初始化bean");
}
public void doSome() {
System.out.println("4.使用bean");
}
@PreDestroy
public void destroyBean() {
System.out.println("5.销毁bean");
}
}
/**
* Spring 核心配置类
*/
@Configuration
@ComponentScan("com.ltb.demo")
public class ContextConfig {
}
/**
* 测试类
*/
class UserTest {
@Test
void test1() {
ApplicationContext context = new AnnotationConfigApplicationContext(ContextConfig.class);
User user = context.getBean("user", User.class);
user.doSome();
((AnnotationConfigApplicationContext) context).close();
}
}
测试方法执行结果:
注意:
-
使用 @PostConstruct 来标识一个初始化方法,这个方法是程序员自定义的
-
使用 @PreDestroy 来标识一个销毁方法,这个方法也是程序员自定义的
-
只有正常关闭 spring 容器,bean 的销毁方法才会被调用
这两个注解属于 JDK 扩展包,所以不在 JDK 当中,需要额外引入以下依赖:【如果是 JDK8 的话不需要引入。高于 JDK11 或低于 JDK8 需要引入】
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
一定要注意:如果你用 Spring 6,要知道 Spring 6 不再支持 JavaEE,它支持的是 JakartaEE9。(Oracle 把 JavaEE 贡献给 Apache 了,Apache 把 JavaEE 的名字改成 JakartaEE 了,大家之前所接触的所有的 javax.* 包名统一修改为 jakarta.* 包名了)
Bean 的生命周期之七步
在以上的 5 步中,第 3 步是初始化 Bean,如果你还想在初始化前后添加代码,可以加入 "Bean 后处理器"
编写一个类,实现 BeanPostProcessor 接口,并将这个类对象交给 Spring 容器管理,那么这个类就是一个 Bean 后处理器了。代码如下:
@Component
public class LogBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean 后处理器的 before 方法执行,即将开始初始化");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean 后处理器的 after 方法执行,已完成初始化");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
注意:如果是在 XML 文件中配置的 Bean 后处理器将只会作用于当前配置文件中所有的 Bean。
其他代码均不变,重新运行测试方法,运行结果如下:
如果加上后处理器的话,Bean 的生命周期就是七步了:
Bean 的生命周期之十步
Bean 的生命周期步骤还可以更细粒度的划分,在七步的基础上,分别在后处理器的 before 方法前和后、销毁 Bean 前再各加一步,构成 Bean 生命周期的十个阶段。
相关接口如下:
- BeanNameAware:Spring 会将 Bean 的名字传给这个接口的实现方法。
- BeanClassLoaderAware:Spring 会将加载这个 Bean 的类加载器传给这个接口的实现方法。
- BeanFactoryAware:Spring 会将生产这个 Bean 的工厂传给这个接口的实现方法。
- InitializingBean:这个接口的方法,会在后处理器的 before 执行之后,Bean 初始化方法执行之前执行。
- DisposableBean:这个接口的方法,会在销毁 Bean 方法执行之前执行。
其中,Aware 接口的方法执行时机是属性赋值完之后、后处理器 before 执行之前执行。
具体代码非常简单这里就不编写了,直接上运行结果:
Bean 的作用域不同,管理方式不同
Spring 根据 Bean 的作用域来选择管理方式,作用域是 singleton 的 Bean,Spring 能够精准地知道该 Bean 什么时候被初始化,什么时候被销毁,所以可以完完整整的走完上述的 10 个步骤;
对于作用域是 prototype 的 Bean,初始化好了之后 Spring 将不再负责,Bean 的实例交给程序员管理,Spring 不再追踪其生命周期,所以只有上述 10 个步骤的前 8 步。