08 Bean的生命周期
8.1 什么是 Bean 的生命周期¶
Spring 其实就是一个管理 Bean 对象的工厂。它负责对象的创建,对象的销毁等。 所谓的生命周期就是:对象从创建开始到最终销毁的整个过程。 什么时候创建 Bean 对象? 创建 Bean 对象的前后会调用什么方法? Bean 对象什么时候销毁? Bean 对象的销毁前后调用什么方法?
8.2 为什么要知道 Bean 的生命周期¶
其实生命周期的本质是:在哪个时间节点上调用了哪个类的哪个方法。 我们需要充分的了解在这个生命线上,都有哪些特殊的时间节点。 只有我们知道了特殊的时间节点都在哪,到时我们才可以确定代码写到哪。 我们可能需要在某个特殊的时间点上执行一段特定的代码,这段代码就可以放到这个节点上。当生命线走到这里的时候,自然会被调用。
8.3 Bean 的生命周期之 5 步¶
Bean 生命周期的管理,可以参考 Spring 的源码:AbstractAutowireCapableBeanFactory 类的 doCreateBean () 方法。 Bean 生命周期可以粗略的划分为五大步: - 第一步:实例化 Bean - 第二步:Bean 属性赋值 - 第三步:初始化 Bean - 第四步:使用 Bean - 第五步:销毁 Bean ![[08.03-2.png]] 编写测试程序:
定义一个 Bean ```java title:User package com.powernode.spring6.bean;
/** * @author 动力节点 * @version 1.0 * @className User * @since 1.0 */ public class User { private String name;
public User() {
System.out.println("1.实例化Bean");
}
public void setName(String name) {
this.name = name;
System.out.println("2.Bean属性赋值");
}
public void initBean(){
System.out.println("3.初始化Bean");
}
public void destroyBean(){
System.out.println("5.销毁Bean");
}
}
```xml title:spring.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userBean" class="com.powernode.spring6.bean.User" init-method="initBean" destroy-method="destroyBean">
<property name="name" value="zhangsan"/>
</bean>
</beans>
```java title:BeanLifecycleTest package com.powernode.spring6.test;
import com.powernode.spring6.bean.User; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
/** * @author 动力节点 * @version 1.0 * @className BeanLifecycleTest * @since 1.0 */ public class BeanLifecycleTest { @Test public void testLifecycle(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); User userBean = applicationContext.getBean("userBean", User.class); System.out.println("4.使用Bean"); // 只有正常关闭spring容器才会执行销毁方法 ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext; context.close(); } }
执行结果:
![[08.03-3.png]]
需要注意的:
- 第一:**只有正常关闭 spring 容器,bean 的销毁方法才会被调用。**
- 第二:**`ClassPathXmlApplicationContext` 类才有 close () 方法。**
- 第三:**配置文件中的 `init-method` 指定初始化方法。`destroy-method` 指定销毁方法。**
---
## 8.4 Bean 生命周期之 7 步
在以上的 5 步中,第 3 步是初始化 Bean,如果你还想在初始化前和初始化后添加代码,可以加入“Bean 后处理器”。
编写一个类实现 BeanPostProcessor 类,并且重写 before 和 after 方法:
```java title:LogBeanPostProcessor
package com.powernode.spring6.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* @author 动力节点
* @version 1.0
* @className LogBeanPostProcessor
* @since 1.0
*/
public class LogBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean后处理器的before方法执行,即将开始初始化");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean后处理器的after方法执行,已完成初始化");
return bean;
}
}
在 spring. xml 文件中配置“Bean 后处理器”: ```xml title:spring.xml
一定要注意:在 spring. xml 文件中配置的 Bean 后处理器将作用于当前配置文件中所有的 Bean。
执行测试程序:
![[08.04-1.png]]
如果加上 Bean 后处理器的话,Bean 的生命周期就是 7 步了:
![[08.04-2.png]]
---
## 8.5 Bean 生命周期之 10 步
如果根据源码跟踪,可以划分更细粒度的步骤,10 步:
![[08.05-1.png]]
上图中检查 Bean 是否实现了 Aware 的相关接口是什么意思?
Aware 相关的接口包括:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
- 当 Bean 实现了 BeanNameAware,Spring 会将 Bean 的名字传递给 Bean。
- 当 Bean 实现了 BeanClassLoaderAware,Spring 会将加载该 Bean 的类加载器传递给 Bean。
- 当 Bean 实现了 BeanFactoryAware,Spring 会将 Bean 工厂对象传递给 Bean。
测试以上 10 步,可以让 User 类实现 5 个接口,并实现所有方法:
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
- InitializingBean
- DisposableBean
代码如下:
```java title:User
package com.powernode.spring6.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
/**
* @author 动力节点
* @version 1.0
* @className User
* @since 1.0
*/
public class User implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {
private String name;
public User() {
System.out.println("1.实例化Bean");
}
public void setName(String name) {
this.name = name;
System.out.println("2.Bean属性赋值");
}
public void initBean(){
System.out.println("6.初始化Bean");
}
public void destroyBean(){
System.out.println("10.销毁Bean");
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("3.类加载器:" + classLoader);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("3.Bean工厂:" + beanFactory);
}
@Override
public void setBeanName(String name) {
System.out.println("3.bean名字:" + name);
}
@Override
public void destroy() throws Exception {
System.out.println("9.DisposableBean destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("5.afterPropertiesSet执行");
}
}
```java title:LogBeanPostProcessor package com.powernode.spring6.bean;
import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor;
/** * @author 动力节点 * @version 1.0 * @className LogBeanPostProcessor * @since 1.0 */ public class LogBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("4.Bean后处理器的before方法执行,即将开始初始化"); return bean; }
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("7.Bean后处理器的after方法执行,已完成初始化");
return bean;
}
}
执行结果:
![[08.05-2.png]]
通过测试可以看出来:
- **InitializingBean 的方法早于 init-method 的执行。**
- **DisposableBean 的方法早于 destroy-method 的执行。**
对于 SpringBean 的生命周期,掌握之前的 7 步即可。够用。
---
## 8.6 Bean 的作用域不同,管理方式不同
Spring 根据 Bean 的作用域来选择管理方式。
- 对于 singleton 作用域的 Bean,Spring 能够精确地知道该 Bean 何时被创建,何时初始化完成,以及何时被销毁;
- 而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。
我们把之前 User 类的 spring. xml 文件中的配置 scope 设置为 prototype:
```xml title:spring.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置Bean -->
<bean id="userBean" class="com.powernode.spring6.bean.User" init-method="initBean" destroy-method="destroyBean" scope="prototype">
<property name="name" value="zhangsan"/>
</bean>
<!-- 配置Bean后处理器:注意,Bean后处理器也是一个Bean -->
<bean class="com.powernode.spring6.bean.LogBeanPostProcessor"/>
</beans>
执行测试程序: ![[08.06-1.png]] 通过测试一目了然。只执行了前 8 步,第 9 和 10 都没有执行。
8.7 自己 new 的对象如何让 Spring 管理¶
有些时候可能会遇到这样的需求,某个 java 对象是我们自己 new 的,然后我们希望这个对象被 Spring 容器管理,怎么实现?
```java title:User package com.powernode.spring6.bean;
/** * @author 动力节点 * @version 1.0 * @className User * @since 1.0 */ public class User { }
```java title:RegisterBeanTest
package com.powernode.spring6.test;
import com.powernode.spring6.bean.User;
import org.junit.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
/**
* @author 动力节点
* @version 1.0
* @className RegisterBeanTest
* @since 1.0
*/
public class RegisterBeanTest {
@Test
public void testBeanRegister(){
// 自己new的对象
User user = new User();
System.out.println(user);
// 创建 默认可列表BeanFactory 对象
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 注册Bean
factory.registerSingleton("userBean", user);
// 从spring容器中获取bean
User userBean = factory.getBean("userBean", User.class);
System.out.println(userBean);
}
}
执行结果: ![[08.07-1.png]]