观看本文前,我们先思考一个问题,什么是Spring的bean的生命周期?这也是我们在面试的时候,面试官常问的一个问题。
在没有Spring之前,我们创建对象的时候,采用new的方式,当对象不在被使用的时候,由Java的垃圾回收机制回收。
而 Spring 中的对象是 bean,bean 和普通的 Java 对象没啥大的区别,只不过 Spring 不再自己去 new 对象了,而是由 IoC 容器去帮助我们实例化对象并且管理它,我们需要哪个对象,去问 IoC 容器要即可。IoC 其实就是解决对象之间的耦合问题,Spring Bean 的生命周期完全由容器控制。
在这里,我们主要是针对bean 的作用域为singleton的,对于 prototype 的 bean ,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 已经被删除。
Spring Bean 的生命周期核心就分为以下几步:
- 实例化 Instantiation
- 属性赋值 Populate
- 初始化 Initialization
- 销毁 Destruction
实例化 -> 属性赋值 -> 初始化 -> 销毁
ok,接下来,我们用一个bean的创建来体验下Spring Bean的生命周期。
首先,我们先来介绍下什么是FactoryBean?
FactoryBean要和BeanFactory区分开来,BeanFactory是一个Bean工厂,创建和管理bean的工厂,是顶级接口,而FactoryBean 用来自定义Bean的创建过程,完成复杂Bean的定义。
Spring中Bean主要有有两种,一个是定义普通Bean,另一个是工厂Bean(FactoryBean)。FactoryBean是一个工厂bean,可以生成某一个类型的Bean实例,通过实现该接口定制实例化bean的逻辑。
FactoryBean在Spring框架中非常重要,Spring自身就提供了70多个FactoryBean接口的实现,通过 getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。
FactoryBean接口源码:
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
//返回由FactoryBean 创建的Bean实例,如果isSingleton()返回true,该实例会被放到Spring容器的单里缓存池中
@Nullable
T getObject() throws Exception;
//返回FactoryBean创建的Bean的类型
@Nullable
Class<?> getObjectType();
//判断Bean的作用域是singleton还是prototype
default boolean isSingleton() {
return true;
}
}
案例实战
- 配置文件中< bean >的class属性配置的实现类是FactoryBean时,通过getBean()方法返回的不是FactoryBean本身
- 获取的是FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。
- 创建Order实体类
@Data
public class Order {
//订单ID
private int orderId;
//订单名称
private String orderName;
//订单价格
private int price;
}
- 创建OrderFactoryBean
public class OrderFactoryBean implements FactoryBean<Order> {
public OrderFactoryBean() {
System.out.println("FactoryBean构造方法执行");
}
private String orderInfo;
//设置orderInfo
public void setOrderInfo(String orderInfo) {
this.orderInfo = orderInfo;
}
// 11@测试订单@7999
@Override
public Order getObject() throws Exception {
String[] split = orderInfo.split("@");
Order order = new Order();
order.setOrderId(Integer.parseInt(split[0]));
order.setOrderName(split[1]);
order.setPrice(Integer.parseInt(split[2]));
return order;
}
//返回当前bean类型
@Override
public Class<?> getObjectType() {
return Order.class;
}
//返回当前bean是否为单例
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
- xml配置文件
<bean id="order" class="com.lixiang.factory.OrderFactoryBean">
<property name="orderInfo" value="11@测试订单@7999"/>
</bean>
- 主类测试
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:application.xml");
Order order = (Order) context.getBean("order");
System.out.println(order);
Object obj = context.getBean("&order");
System.out.println(obj);
}
接下来,我们再来看一下BeanFactoryPostProcessor。
BeanFactoryPostProcessor是Spring框架中一个重要的扩展接口,可以在spring的bean创建之前,可以修改Bean的定义属性,注入第三方数据等。它是在 Spring 容器加载定义 bean 的 XML 文件之后,在 bean 实例化之前执行的,对Bean进行后置处理。它的执行逻辑在BeanFactory初始化时执行,在BeanFactory的后置处理器(BeanPostProcessor)之前执行。
作用:
- 读取应用程序上下文(ApplicationContext)中的所有Bean定义。
- 修改定义中的属性值等信息。
- 对修改后的定义进行处理,使其达到预期效果。
- 将修改后的Bean定义反馈到容器中,容器将重新执行Bean创建和初始化的过程
接口代码
//ConfigurableListableBeanFactory 可以获取bean定义信息,里面进行修改bean定义
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
案例实战
- 定义一个
OrderBeanFactoryPostProcessor
,修改某个 bean 从单例改为多例,然后触发init方法。
public class OrderBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public OrderBeanFactoryPostProcessor(){
System.out.println("OrderBeanFactoryPostProcessor构造方法执行");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] beanStr = beanFactory.getBeanDefinitionNames();
for (String beanName : beanStr) {
if ("order".equals(beanName)) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
beanDefinition.setScope(ConfigurableBeanFactory.SCOPE_SINGLETON);
}
}
}
//testInit 初始化方法
public void testInit(){
System.out.println("OrderBeanFactoryPostProcessor testInit 方法被调用,执行初始化逻辑");
}
}
- 配置xml
<bean id="customFactoryPostProcessor" class="com.lixiang.factory.OrderBeanFactoryPostProcessor" init-method="testInit"></bean>
- 编写测试主类
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:application.xml");
Object obj1 = context.getBean("&order");
Object obj2 = context.getBean("&order");
System.out.println(obj1);
System.out.println(obj2);
}
Ok,说完BeanFactoryPostProcessor,我们再来看下BeanPostProcessor。
BeanPostProcessor是Spring IOC容器提供的一个扩展机制,用于拦截和修改实例化的Bean对象的过程。默认是对整个Spring容器中【所有的bean】进行处理,如果要对具体某个bean进行处理,通过方法参数判断即可。在容器实例化Bean对象后 (执行构造函数),初始化方法执行【前后】的回调方法,提供Bean实例初始化期间加入自定义逻辑。
案例实战
- 编写OrderBeanPostProcessor
public class OrderBeanPostProcessor implements BeanPostProcessor {
public OrderBeanPostProcessor() {
System.out.println("BeanPostProcessor构造方法执行");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor postProcessAfterInitialization 调用 beanName="+beanName);
if(beanName.equalsIgnoreCase("order")){
Order order = (Order)bean;
order.setOrderName("修改后的订单名称");
return BeanPostProcessor.super.postProcessAfterInitialization(order, beanName);
}
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
- 编写xml配置Order对象属性
<bean id="orderBeanPostProcessor" class="com.lixiang.factory.OrderBeanPostProcessor"></bean>
<bean id="order" class="com.lixiang.domain.Order">
<property name="orderId" value="113726"/>
<!-- 这里我们将订单名称设置为测试订单 -->
<property name="orderName" value="测试订单"/>
<property name="price" value="2131213"/>
</bean>
- 编写测试代码
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:application.xml");
Order order = (Order) context.getBean("order");
System.out.println(order);
}
- 注意
- BeanPostProcessor 是在 spring 容器加载了 bean 的定义文件,且实例化 bean 之后执行
- BeanPostProcessor 的执行顺序是在 BeanFactoryPostProcessor 之后
- BeanFactoryPostProcessor 和 BeanPostProcessor 都是处理 bean 的生命周期中拓展点,使用场景不同
- BeanFactoryPostProcessor 作用于 bean 实例化之前,读取配置元数据 BeanDefinition ,且可以修改
- BeanPostProcessor 作用于 bean 的实例化过程中,可以改变 bean 实例的值
还有几个接口,我们简单了解下,这快就不做演示了。
- BeanNameAware
BeanNameAware接口是为了让自身Bean能够感知到,获取到自身在Spring容器中的id或name属性。让Bean获取自己在BeanFactory配置中的名字(根据情况是id或者name)。
Spring自动调用。并且会在Spring自身完成Bean配置之后,且在调用任何Bean生命周期回调(初始化或者销毁)方法之前就调用这个方法。换言之,在程序中使用BeanFactory.getBean(String beanName)之前,Bean的名字就已经设定好了。
- BeanFactoryAware
BeanFactoryAware接口是Spring框架中的一个接口,用于在Bean实例化后,将BeanFactory实例注入到Bean中。通过实现该接口,Bean可以获取到BeanFactory实例,从而可以在运行时动态获取其他Bean的实例。
具体来说,BeanFactoryAware接口的作用是让Bean能够感知到所在的BeanFactory,从而可以在需要时获取其他Bean的实例。这对于需要动态获取其他Bean的实例的情况非常有用,例如在AOP中需要获取代理对象等。
- ApplicationContextAware
在spring项目中,类之间的关系是spring容器来管理的,但是一个项目中有些类不受spring容器管理,缺需要使用受spring管理的bean,这时候不能通过正常的方式注入bean,这时候spring给我们提供了ApplicationContextAware接口,我们可以编写一个工具类来实现ApplicationContextAware,当一个类实现ApplicationContextAware接口后,当这个类被spring加载后,就能够在这个类中获取到spring的上下文操作符ApplicationContext,通过ApplicationContext 就能够轻松的获取所有的spring管理的bean。
- Initializingbean
Initializingbean接口只有一个afterPropertiesSet方法,实现了这个接口的类在初始化Bean时会执行这个方法。所以这个接口的用途就是用来实现初始化数据用的。
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
- DisposableBean
该接口的作用是:允许一个bean在它的所有必须属性被BeanFactory设置后,来执行初始化的工作,该接口中只有一个方法,afterPropertiesSet。
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
ok,现在我们用Order实现以上的接口。
public class Order implements BeanNameAware, BeanFactoryAware,
ApplicationContextAware, InitializingBean, DisposableBean {
private int orderId;
private String orderName;
private int price;
public Order() {
System.out.println("Order - 构造方法执行,创建对象");
}
public Order(int orderId, String orderName, int price) {
this.orderId = orderId;
this.orderName = orderName;
this.price = price;
}
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "Order{" +
"orderId=" + orderId +
", orderName='" + orderName + '\'' +
", price=" + price +
'}';
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("Order - BeanFactoryAware - setBeanFactory 方法被调用");
}
@Override
public void setBeanName(String s) {
System.out.println("Order - BeanNameAware - setBeanName 方法被调用");
}
@Override
public void destroy() throws Exception {
System.out.println("Order - DisposableBean - destroy 方法被调用");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Order - InitializingBean - afterPropertiesSet 方法被调用");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("Order - ApplicationContextAware - setApplicationContext 方法被调用");
}
}
创建Order对象,查看方法执行调用链。
方法调用链图解
源码分析目标,关键就在于AbstractApplicationContext 类 的 refresh 方法
OK,接下来我们来看看refresh的源码分析,基本上整一个spring生命周期都这这个方法里执行,我们来看看这个核心方法里面都做了什么
public void refresh() throws BeansException, IllegalStateException {
//采用对象锁,保证多线程环境下,在容器正在启动/关闭时, 另一个启动/关闭操作会被阻塞
synchronized (this.startupShutdownMonitor) {
//统计Spring应用程序的启动时间,并输出到log
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
//1.调用子类覆盖的方法prepareRefresh(),为当前的工厂进行启动数据准备工作
prepareRefresh();
/**
* 2.调用子类覆盖的方法obtainFreshBeanFactory(),创建新的BeanFactory, 默认实现是DefaultListableBeanFactory
* 解析xml, 生成BeanDefinition 并注册到 BeanDefinitionRegistry
*
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//3.beanFactory准备工作,调用子类覆盖的方法prepareBeanFactory(),对新的BeanFactory进行各种后置处理
prepareBeanFactory(beanFactory);
try {
//4.beanFactory准备工作完成后,继续进行的【后置处理】
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
//5.BeanFactoryPostProcessor
//Spring 启动时查找所有实现 BeanFactoryPostProcessor 接口的类,并逐一调用其 postProcessBeanFactory 方法
invokeBeanFactoryPostProcessors(beanFactory);
//6.BeanPostProcessor
//注册 BeanPostProcessor,负责为该 Bean 对象创建代理对象
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
//7.初始化信息源,用来支持国际化
initMessageSource();
//8.初始化事件广播器,用来支持了Spring事件机制
initApplicationEventMulticaster();
//9.留给子类实现的初始化操作,即调用自定义的回调方法
onRefresh();
//10.注册实现了ApplicationListener接口的类
registerListeners();
/**
* 11.实例化所有剩余的单例Bean(非懒加载的单例bean),注意这里要区分单例和非单例Bean,主要下面的工作
* 填充属性
* 调用初始化方法 afterPropertiesSet、init-method方法
* 调用BeanPostProcessor 后置处理器 postProcessBeforeInitialization和postProcessAfterInitialization执行
*/
finishBeanFactoryInitialization(beanFactory);
//12.事件发布,发送ContextRefreshedEvent事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
// 销毁已经创建的单例bean
destroyBeans();
// 将 context 的 active 属性重置为 false
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
// 重置Spring IOC中的共享缓存,避免单例bean的引用问题
resetCommonCaches();
//更新contextRefresh的状态
contextRefresh.end();
}
}
}
总结
- 首先根据配置情况调用 Bean 构造方法或工厂方法实例化 Bean。
- 然后利用反射创建对象设置Bean 中所有属性值的配置注入。
- 如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。
- 如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。
- 如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。
- 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的预初始化方法 postProcessBeforeInitialzation() 对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的。
- 如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法,如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。
- 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization()。此时,Bean 已经可以被应用系统使用了。
- 如果在 中指定了该 Bean 的作用范围为 scope=“singleton”,则将该 Bean 放入 Spring IoC 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 中指定了该 Bean 的作用范围为 scope=“prototype”,则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean。
- 如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法将 Spring 中的 Bean 销毁;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。
ok,那么至此,Spring Bean的整一个生命周期全部解析完成。