欢送大家关注我的微信公众号【老周聊架构】,Java 后端支流技术栈的原理、源码剖析、架构以及各种互联网高并发、高性能、高可用的解决方案。
一、前言
明天咱们来说一说 Spring Bean 的生命周期,小伙伴们应该在面试中常常遇到,这是失常景象。因为 Spring Bean 的生命周期是除了 IoC、AOP 几个外围概念之外最重要概念,大家务必拿下。可 Spring 源代码又比较复杂,跟着跟着就不晓得跟到哪里去了,不太好拿下呀。这倒是真的,而且网上一上来就各种贴流程源码,对初学者来说是真的一脸懵逼,就像字都看的懂,但连在一块就不晓得意思了,太绕了。
本文老周试着讲的通俗易懂些,让更多的小伙伴们轻松的读懂 Spring Bean 的生命周期,并有对它有持续钻研学习的想法,那我写此文的目标也就达到了。
咱们讲 Spring Bean 的生命周期之前先来理解两个概念:
1.1 什么是 Bean
咱们来看下 Spring Framework 的官网文档:
In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application. Beans, and the dependencies among them, are reflected in the configuration metadata used by a container.
简而言之,bean 是由 Spring IoC 容器实例化、组装和治理的对象。
1.2 什么是 Spring Bean 的生命周期
对于一般的 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
实例化 -> 属性赋值 -> 初始化 -> 销毁
只有四个步骤,这样拆解的话是不是感觉也不难?不像其他人写的那样间接一上来就各种 BeanPostProcessor、BeanFactoryPostProcessor 全副怼进流程里去,别说读者看着头大,本人写的可能短时间内还记得流程,隔个一段时间,你可能都不晓得本人写了个啥。
原本老周想通过 Bean 创立流程入口
AbstractApplicationContext#refresh() 办法的 finishBeanFactoryInitialization(beanFactory) 处带大家跟一下源码,想了想还是不带入过多的代码进来,间接给到最终的次要逻辑。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 实例化阶段
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
...
Object exposedObject = bean;
try {
// 属性赋值阶段
this.populateBean(beanName, mbd, instanceWrapper);
// 初始化阶段
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
} catch (Throwable var18) {...}
...
}
至于销毁,是在容器敞开时调用的,详见 ConfigurableApplicationContext#close()
是不是很清新了?至于 BeanPostProcessor、BeanFactoryPostProcessor 以及其余的类,在老周看来,只不过是对主流程四个步骤的一系列扩大点而已。
三、Spring Bean 的生命周期的扩大点
Spring Bean 的生命周期的扩大点超级多,老周这里不可能全部列进去,只说外围的扩大点。这也就是为什么 Spring 的扩展性很好的起因,开了很多的口子,尽可能让某个性能高内聚松耦合,用户须要哪个性能就用哪个,而不是间接来一个大而全的货色。
3.1 Bean 本身的办法
比方构造函数、getter/setter 以及 init-method 和 destory-method 所指定的办法等,也就对应着上文说的实例化 -> 属性赋值 -> 初始化 -> 销毁四个阶段。
3.2 容器级的办法(BeanPostProcessor 一系列接口)
次要是后处理器办法,比方下图的 InstantiationAwareBeanPostProcessor
、BeanPostProcessor
接口办法。这些接口的实现类是独立于 Bean 的,并且会注册到 Spring 容器中。在 Spring 容器创立任何 Bean 的时候,这些后处理器都会产生作用。
3.2.1 InstantiationAwareBeanPostProcessor 源码剖析
咱们翻一下源码发现 InstantiationAwareBeanPostProcessor 是继承了 BeanPostProcessor
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
调用点
Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
返回值:如果返回的不为 null,那么后续的 Bean 的创立流程【实例化、初始化 afterProperties】都不会执行,而是间接应用返回的快捷 Bean,此时的失常执行程序如下:
InstantiationAwareBeanPostProcessor 接口中的 postProcessBeforeInstantiation,在实例化之前调用。
BeanPostProcessor 接口中的 postProcessAfterInitialization,在实例化之后调用。
总之,postProcessBeforeInstantiation 在 doCreateBean 之前调用,也就是在 bean 实例化之前调用的,英文源码正文解释道该办法的返回值会替换本来的 Bean 作为代理,这也是 AOP 等性能实现的关键点。
InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
调用点
boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException
失常状况下在实例化之后在执行 populateBean 之前调用
返回值:如果有指定的 bean 的时候返回 false,那么后续的属性填充和属性依赖注入【populateBean】将不会执行,同时后续的 postProcessPropertyValues 将不会执行, 然而初始化和 BeanPostProcessor 的依然会执行。
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
实例化之后调用,在办法 applyPropertyValues【属性填充】之前
返回值:如果返回 null,那么将不会进行后续的属性填充,比方依赖注入等,如果返回的 pvs 额定的增加了属性,那么后续会填充到该类对应的属性中。
pvs:PropertyValues 对象,用于封装指定类的对象,简略来说就是 PropertyValue 的汇合,外面相当于以 key-value 模式寄存类的属性和值。
pds:PropertyDescriptor 对象数组,PropertyDescriptor 相当于存储类的属性,不过能够调用 set,get 办法设置和获取对应属性的值。
3.2.2 BeanPostProcessor 源码剖析
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
进入初始化接口:
咱们先来看
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
- 首先获取到所有的后置处理器 getBeanPostProcessors()
- 在 for 循环中顺次调用后置处理器的办法
processor.postProcessBeforeInitialization(result, beanName);
- 进入 postProcessBeforeInitialization 办法
org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization
进入 invokeAwareInterfaces(bean);
办法,以后 bean 实现了 ApplicationContextAware 接口。
ApplicationContextAwareProcessor#postProcessBeforeInitialization
首先判断此 bean 是不是各种的 Aware,如果是它列举的那几个 Aware 就获取 Bean 工厂的权限,能够向容器中导入相干的上下文环境,目标是为了 Bean 实例可能获取到相干的上下文,如果不是它列举的几个 Aware,那就调用invokeAwareInterfaces(bean)
,向容器中增加相干接口的上下文环境。
3.3 工厂后处理器办法(BeanFactoryProcessor 一系列接口)
包含 AspectJWeavingEnabler
、CustomAutowireConfigurer
、ConfigurationClassPostProcessor
等。这些都是 Spring 框架中曾经实现好的 BeanFactoryPostProcessor,用来实现某些特定的性能。
咱们晓得 Spring IoC 容器初始化的关键环节就在 org.springframework.context.support.AbstractApplicationContext#refresh
办法中,容器创立的主体流程都在这个办法外面,这个办法是真的重要!!!
对于工厂后处理器办法老周这里间接带你看 invokeBeanFactoryPostProcessors(beanFactory);
办法,这个办法解决的是 BeanFactoryPostProcessor
接口的 Bean。调用办法如下:
跟到最重要的办法里去,代码虽长,但逻辑中规中矩。
BeanFactoryPostProcessor
:所有解决 BeanFactory 的父接口BeanDefinitionRegistryPostProcessor
:实现了 BeanFactoryPostProcessor 接口的接口
流程阐明:
- 调用 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry(registry) 办法。参数 beanFactoryPostProcessors 传入的优先解决掉。而后获取容器注册的,对于这些 Bean 依照 PriorityOrdered 接口、Ordered、没有排序接口的实例别离进行解决。
- 调用 BeanFactoryPostProcessor#postProcessBeanFactory(beanFactory) 办法。备注:BeanDefinitionRegistryPostProcessor 属于 BeanFactoryPostProcessor 子接口。先解决属于 BeanDefinitionRegistryPostProcessor 接口实例的 postProcessBeanFactory(beanFactory) 办法,而后获取容器注册的。对于这些 Bean 依照 PriorityOrdered 接口、Ordered、没有排序接口的实例别离进行解决。
3.4 Bean 级生命周期办法
能够了解为 Bean 类间接实现接口的办法,比方 BeanNameAware
、BeanFactoryAware
、ApplicationContextAware
、InitializingBean
、DisposableBean
等办法,这些办法只对以后 Bean 失效。
3.4.1 Aware 类型的接口
Aware 类型的接口的作用就是让咱们可能拿到 Spring 容器中的一些资源。根本都可能见名知意,Aware 之前的名字就是能够拿到什么资源,例如 BeanNameAware 能够拿到 BeanName,以此类推。调用机会须要留神:所有的 Aware 办法都是 在初始化阶段之前调用的
。
Aware 接口泛滥,这里同样通过分类的形式帮忙大家记忆。Aware 接口具体能够分为两组,至于为什么这么分,详见上面的源码剖析。如下排列程序同样也是 Aware 接口的执行程序,可能见名知意的接口不再解释。
Aware Group1
BeanNameAware
BeanClassLoaderAware
BeanFactoryAware
Aware Group2
EnvironmentAware
EmbeddedValueResolverAware
这个晓得的人可能不多,实现该接口可能获取 Spring EL 解析器,用户的自定义注解须要反对 SPEL 表达式的时候能够应用,十分不便。ApplicationContextAware(ResourceLoaderAware/ApplicationEventPublisherAware/MessageSourceAware)
这几个接口可能让人有点懵,实际上这几个接口能够一起记,其返回值本质上都是以后的 ApplicationContext 对象,因为 ApplicationContext 是一个复合接口,如下:
Aware 调用机会源码剖析
能够看到并不是所有的 Aware 接口都应用同样的形式调用。Bean××Aware 都是在代码中间接调用的,而 ApplicationContext 相干的 Aware 都是通过 BeanPostProcessor#postProcessBeforeInitialization() 实现的。感兴趣的能够本人看一下 ApplicationContextAwareProcessor 这个类的源码,就是判断以后创立的 Bean 是否实现了相干的 Aware 办法,如果实现了会调用回调办法将资源传递给 Bean。
BeanPostProcessor 的调用机会也能在这里体现,包围住 invokeInitMethods 办法,也就阐明了在初始化阶段的前后执行。
对于 Aware 接口的执行程序,其实只须要记住第一组在第二组执行之前就行了。
3.4.2 生命周期接口
至于剩下的两个生命周期接口就很简略了,实例化和属性赋值都是 Spring 帮忙咱们做的,可能本人实现的有初始化和销毁两个生命周期阶段。
InitializingBean
对应生命周期的初始化阶段,在下面源码的invokeInitMethods(beanName, wrappedBean, mbd);
办法中调用。
有一点须要留神,因为 Aware 办法都是执行在初始化办法之前,所以能够在初始化办法中放心大胆的应用 Aware 接口获取的资源,这也是咱们自定义扩大 Spring 的罕用形式。
除了实现 InitializingBean 接口之外还能通过注解或者 xml 配置的形式指定初始化办法,至于这几种定义形式的调用程序其实没有必要记。因为这几个办法对应的都是同一个生命周期,只是实现形式不同,咱们个别只采纳其中一种形式。
DisposableBean
相似于 InitializingBean,对应生命周期的销毁阶段,以ConfigurableApplicationContext#close()
办法作为入口,实现是通过循环取所有实现了 DisposableBean 接口的 Bean 而后调用其 destroy() 办法,感兴趣的能够自行跟一下源码。
3.5 Spring Bean 生命周期流程图
四、罕用接口阐明
4.1 BeanNameAware
该接口只有一个办法 setBeanName(String name)
,用来获取 bean 的 id 或者 name
。
4.2 BeanFactoryAware
该接口只有一个办法 setBeanFactory(BeanFactory beanFactory)
,用来获取 以后环境中的 BeanFactory
。
4.3 ApplicationContextAware
该接口只有一个办法 setApplicationContext(ApplicationContext applicationContext)
,用来获取 以后环境中的 ApplicationContext
。
4.4 InitializingBean
该接口只有一个办法 afterPropertiesSet()
,在 属性注入实现后调用
。
4.5 DisposableBean
该接口只有一个办法 destroy()
,在容器销毁的时候调用,在 用户指定的 destroy-method 之前调用
。
4.6 BeanPostProcessor
该接口有两个办法:
postProcessBeforeInitialization(Object bean, String beanName)
:在初始化之前
调用此办法postProcessAfterInitialization(Object bean, String beanName)
:在初始化之后
调用此办法
通过办法签名咱们能够晓得,咱们能够通过 beanName 来筛选出咱们须要进行个性化定制的 bean。
4.7 InstantiationAwareBeanPostProcessor
该类是 BeanPostProcessor 的子接口,罕用的有如下三个办法:
postProcessBeforeInstantiation(Class beanClass, String beanName)
:在 bean实例化之前
调用postProcessProperties(PropertyValues pvs, Object bean, String beanName)
:在 bean实例化之后、设置属性前
调用postProcessAfterInstantiation(Class beanClass, String beanName)
:在 bean实例化之后
调用
五、代码演示
思路:创立一个类 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() 办法");
}
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 控制台后果打印