一、前言

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 所指定的方法等,也就对应着上文说的实例化 -> 属性赋值 -> 初始化 -> 销毁四个阶段。

20210707002134280.png

3.2 容器级的方法(BeanPostProcessor 一系列接口)

主要是后处理器方法,比如下图的 InstantiationAwareBeanPostProcessor、BeanPostProcessor 接口方法。这些接口的实现类是独立于 Bean 的,并且会注册到 Spring 容器中。在 Spring 容器创建任何 Bean 的时候,这些后处理器都会发生作用。

20210707225212729.png

3.3 Spring源码跟进

由于篇幅和时间原因,这里先不进行源码的整理,等有空再来自己整理一翻吧哈哈哈

源码根据参考:一文读懂Spring Bean生命周期-CSDN

四、总结

4.1 bean生命周期流程图

20210710134349143.png

2023-12-29T13:58:34.694948676-eycqmfuf.jpg

4.1.1 整体流程解释

  1. BeanDefinition

    • 作用:定义了 Bean 的配置信息,包括类名、属性、构造方法参数等。

    • 使用场景:在 Spring 配置文件或注解中定义 Bean 时,Spring 会将这些配置解析成 BeanDefinition 对象。

  2. InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation

    • 作用:在 Bean 实例化之前执行,可以返回一个代理对象来代替真实对象。

    • 使用场景:用于 AOP 的场景,比如创建一个代理 Bean。

  3. Bean 实例化

    • 作用:根据 BeanDefinition 创建 Bean 的实例。

    • 使用场景:Spring 容器启动时,或者获取 Bean 时,如果 Bean 还未创建,则会触发实例化。

  4. InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation

    • 作用:在 Bean 实例化之后,设置属性之前调用。

    • 使用场景:可以在这个阶段进行自定义逻辑处理,比如字段的检查。

  5. InstantiationAwareBeanPostProcessor#postProcessProperties

    • 作用:对 Bean 的属性进行处理。

    • 使用场景:比如可以用于依赖注入中的属性填充。

  6. Bean属性赋值

    • 作用:根据 BeanDefinition 中的配置为 Bean 的属性赋值。

    • 使用场景:在 Bean 创建过程中自动注入配置的属性。

  7. BeanNameAware#setBeanName

    • 作用:注入当前 Bean 的名称。

    • 使用场景:当 Bean 需要知道自己在容器中的名字时使用。

  8. BeanClassLoaderAware#setBeanClassLoader

    • 作用:注入 ClassLoader。

    • 使用场景:当 Bean 需要访问 ClassLoader 时使用。

  9. BeanFactoryAware#setBeanFactory

    • 作用:注入 BeanFactory。

    • 使用场景:当 Bean 需要访问 Spring 容器时使用。

  10. BeanPostProcessor#postProcessBeforeInitialization

    • 作用:在 Bean 初始化之前执行。

    • 使用场景:可以用于自定义逻辑处理,比如检查是否所有必需的属性已设置。

  11. InitializingBean#afterPropertiesSet

    • 作用:当所有 Bean 属性都已经设置好后执行。

    • 使用场景:可以用于检查 Bean 的配置是否正确。

  12. init-method属性配置的初始化方法

    • 作用:调用自定义的初始化方法。

    • 使用场景:用于 Bean 需要执行自定义初始化逻辑时。

  13. 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();
	}
}

5.7 控制台结果打印

20210711212237789.png