我之前在准备面试时,去网上搜过答案,大多以下图给出的流程作为答案。

但是当我第一次看到该图时,就产生了很多困扰.

“Aware,BeanPostProcessor......这些都是什么啊?而且这么多步骤,太多了,该怎么记啊?”。

其实要记忆该过程,还是需要我们先去理解.

本文将从以下两方面去帮助理解 Bean 的生命周期:

  1. 生命周期的概要流程:对 Bean 的生命周期进行概括,并且结合代码来理解;
  2. 扩展点的作用:详细介绍 Bean 生命周期中所涉及到的扩展点的作用。

3. 生命周期的概要流程

Bean 的生命周期概括起来就是 :

4 个阶段

  1. 实例化(Instantiation)
  2. 属性赋值(Populate)
  3. 初始化(Initialization)
  4. 销毁(Destruction)

  1. 实例化:第 1 步,实例化一个 bean 对象;
  2. 属性赋值:第 2 步,为 bean 设置相关属性和依赖;
  3. 初始化:第 3~7 步,步骤较多,其中第 5、6 步为初始化操作,第 3、4 步为在初始化前执行,第 7 步在初始化后执行,该阶段结束,才能被用户使用;
  4. 销毁:第 8~10步,第8步不是真正意义上的销毁(还没使用呢),而是先在使用前注册了销毁的相关调用接口,为了后面第9、10步真正销毁 bean 时再执行相应的方法。

下面我们结合代码来直观的看下,在 doCreateBean() 方法中能看到依次执行了这 4 个阶段:

// AbstractAutowireCapableBeanFactory.java
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {// 1\. 实例化BeanWrapper instanceWrapper = null;if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}Object exposedObject = bean;try {// 2\. 属性赋值populateBean(beanName, mbd, instanceWrapper);// 3\. 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);}// 4\. 销毁-注册回调接口try {registerDisposableBeanIfNecessary(beanName, bean, mbd);}return exposedObject;
}

由于初始化包含了第 3~7步,较复杂.

所以我们进到 initializeBean() 方法里具体看下其过程(注释的序号对应图中序号):

// AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {// 3\. 检查 Aware 相关接口并设置相关依赖if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {invokeAwareMethods(beanName, bean);}// 4\. BeanPostProcessor 前置处理Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}// 5\. 若实现 InitializingBean 接口,调用 afterPropertiesSet() 方法// 6\. 若配置自定义的 init-method方法,则执行try {invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}// 7\. BeanPostProceesor 后置处理if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;
}

在 invokInitMethods() 方法中会检查 InitializingBean 接口和 init-method 方法,

销毁的过程也与其类似:

// DisposableBeanAdapter.java
public void destroy() {// 9\. 若实现 DisposableBean 接口,则执行 destory()方法if (this.invokeDisposableBean) {try {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {((DisposableBean) this.bean).destroy();return null;}, this.acc);}else {((DisposableBean) this.bean).destroy();}}}// 10\. 若配置自定义的 detory-method 方法,则执行if (this.destroyMethod != null) {invokeCustomDestroyMethod(this.destroyMethod);}else if (this.destroyMethodName != null) {Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);if (methodToInvoke != null) {invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));}}
}

从 Spring 的源码我们可以直观的看到其执行过程.

而我们记忆其过程便可以从这 4 个阶段出发,实例化、属性赋值、初始化、销毁。

其中细节较多的便是初始化,涉及了 Aware、BeanPostProcessor、InitializingBean、init-method 的概念。

这些都是 Spring 提供的扩展点,其具体作用将在下一节讲述。

3. 扩展点的作用

3.1 Aware 接口

若 Spring 检测到 bean 实现了 Aware 接口,则会为其注入相应的依赖。

所以通过让bean 实现 Aware 接口,则能在 bean 中获得相应的 Spring 容器资源

Spring 中提供的 Aware 接口有:

  1. BeanNameAware:注入当前 bean 对应 beanName;
  2. BeanClassLoaderAware:注入加载当前 bean 的 ClassLoader;
  3. BeanFactoryAware:注入 当前BeanFactory容器 的引用。

其代码实现如下:

// AbstractAutowireCapableBeanFactory.java
private void invokeAwareMethods(final String beanName, final Object bean) {if (bean instanceof Aware) {if (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);}if (bean instanceof BeanClassLoaderAware) {((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);}if (bean instanceof BeanFactoryAware) {((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);}}
}

以上是针对 BeanFactory 类型的容器,而对于 ApplicationContext 类型的容器,也提供了 Aware 接口.

只不过这些 Aware 接口的注入实现,是通过 BeanPostProcessor 的方式注入的,但其作用仍是注入依赖。

  1. EnvironmentAware:注入 Enviroment,一般用于获取配置属性;

2.EmbeddedValueResolverAware:注入 EmbeddedValueResolver(Spring EL解析器),一般用于参数解析;

3.ApplicationContextAware(ResourceLoader、ApplicationEventPublisherAware、MessageSourceAware):注入 ApplicationContext 容器本身。

其代码实现如下:

// ApplicationContextAwareProcessor.java
private void invokeAwareInterfaces(Object bean) {if (bean instanceof EnvironmentAware) {((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());}if (bean instanceof EmbeddedValueResolverAware) {((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);}if (bean instanceof ResourceLoaderAware) {((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);}if (bean instanceof ApplicationEventPublisherAware) {((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);}if (bean instanceof MessageSourceAware) {((MessageSourceAware)bean).setMessageSource(this.applicationContext);}if (bean instanceof ApplicationContextAware) {((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);}}

3.2 BeanPostProcessor

BeanPostProcessor 是 Spring 为修改 bean提供的强大扩展点.

其可作用于容器中所有 bean,其定义如下:

public interface BeanPostProcessor {// 初始化前置处理default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}// 初始化后置处理default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}}

常用场景有:

  1. 对于标记接口的实现类,进行自定义处理。

例如3.1节中所说的ApplicationContextAwareProcessor,为其注入相应依赖;

再举个例子,自定义对实现解密接口的类,将对其属性进行解密处理;

  1. 为当前对象提供代理实现。例如 Spring AOP 功能,生成对象的代理类,然后返回。
// AbstractAutoProxyCreator.java
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {TargetSource targetSource = getCustomTargetSource(beanClass, beanName);if (targetSource != null) {if (StringUtils.hasLength(beanName)) {this.targetSourcedBeans.add(beanName);}Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);this.proxyTypes.put(cacheKey, proxy.getClass());// 返回代理类return proxy;}return null;
}

3.3 InitializingBean 和 init-method

InitializingBean 和 init-method 是 Spring 为 bean 初始化提供的扩展点。

InitializingBean接口 的定义如下:

public interface InitializingBean {void afterPropertiesSet() throws Exception;
}

在 afterPropertiesSet() 方法写初始化逻辑。

指定 init-method 方法,指定初始化方法:

<?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="demo" class="com.chaycao.Demo" init-method="init()"/></beans>

DisposableBean 和 destory-method 与上述类似,就不描述了。

4. 总结

最后总结下如何记忆 Spring Bean 的生命周期:

  • 首先是实例化、属性赋值、初始化、销毁这 4 个大阶段;
  • 再是初始化的具体操作,有 Aware 接口的依赖注入、BeanPostProcessor 在初始化前后的处理以及 InitializingBean 和 init-method 的初始化操作;
  • 销毁的具体操作,有注册相关销毁回调接口,最后通过DisposableBean 和 destory-method 进行销毁。

如何记忆 Spring Bean 的生命周期相关推荐

  1. 字节跳动面试题:“请你描述下 Spring Bean 的生命周期?”

    1. 引言 "请你描述下 Spring Bean 的生命周期?",这是面试官考察 Spring 的常用问题,可见是 Spring 中很重要的知识点. 我之前在准备面试时,去网上搜过 ...

  2. 简述 Spring Bean的生命周期

    "请你描述下 Spring Bean 的生命周期?",这是面试官考察 Spring 的常用问题,可见是 Spring 中很重要的知识点. 其实要记忆该过程,还是需要我们先去理解,本 ...

  3. 带你读懂Spring Bean 的生命周期,嘿,就是玩儿~

    带你读懂Spring Bean 的生命周期,嘿,就是玩儿~ 一.前言 今天我们来说一说 Spring Bean 的生命周期,小伙伴们应该在面试中经常遇到,这是正常现象.因为 Spring Bean 的 ...

  4. 再聊Spring Bean的生命周期

    Spring Bean的生命周期是Spring面试热点问题.这个问题即考察对Spring的微观了解,又考察对Spring的宏观认识,想要答好并不容易!本文希望能够从源码角度入手,帮助面试者彻底搞定Sp ...

  5. Spring bean 实现生命周期的三种解决方案

    Spring bean 实现生命周期的三种解决方案 参考文章: (1)Spring bean 实现生命周期的三种解决方案 (2)https://www.cnblogs.com/javawebsoa/a ...

  6. 请解释Spring Bean 的生命周期?

    Spring Bean 的生命周期简单易懂.在一个bean 实例被初始化时,需要执行一系列的初始化操作以达到可用的状态.同样的,当一个bean 不在被调用时需要进行相关的析构操作,并从bean 容器中 ...

  7. Spring Bean的生命周期及接口回调

    本篇介绍Spring框架为Spring Bean生命周期各阶段提供的回调接口,程序通过实现回调接口,可以在IOC容器实例化或销毁Bean的过程中,得到Bean的控制权,并对Bean进行预处理工作.通过 ...

  8. Spring Bean的生命周期(非常详细)

    Spring作为当前Java最流行.最强大的轻量级框架,受到了程序员的热烈欢迎.准确的了解Spring Bean的生命周期是非常必要的.我们通常使用ApplicationContext作为Spring ...

  9. 【Spring Bean的生命周期】

    Spring Bean的生命周期(非常详细) - Chandler Qian - 博客园

  10. Spring Bean的生命周期(二)

    上一篇文章大致说明了Spring Bean的生命周期,本章详细说明各个阶段调用的接口方法. 1.1 - 3.2 对应 实例化 Instantiation 4.1 - 4.2 对应 属性赋值 Popul ...

最新文章

  1. php 二维数组排序函数,php自定义二维数组排序函数array
  2. 好想自己做个迷宫呀!
  3. 华硕ac68u最佳设置_灵耀X2 Pro和ARTone双双登场 华硕一举承包轻奢创作
  4. CLR 基本概念理解
  5. python车辆管理系统_Python简易版停车管理系统
  6. boost::spirit模块演示 AST 生成的计算器示例,AST一旦创建就会被遍历
  7. flume案例-网络数据采集-启动flume
  8. 关于注入(css/c.js)
  9. 题目1065:输出梯形
  10. 【iCore1S 双核心板_FPGA】例程十:乘法器实验——乘法器的使用
  11. Discuz! Ucenter API for JAVA jar包和测试代码
  12. 云数据库时代:企业数据架构的云化智能重构和变革(含大会PPT)
  13. 需要规范日志格式_Node开发的日志规范
  14. MyEclipse6.5设置
  15. 前端------Codepen 用起来非常舒服的工具
  16. 130 个相见恨晚的超实用网站,一次性分享出来,十倍提高工作效率
  17. Rabbitmq Plugin configuration unchanged. 问题完全解决方案
  18. 【原创分享·支付宝支付】HBuilder打包APP调用支付宝客户端支付
  19. 你们这些90后,都是什么神仙小精灵?
  20. 戴尔服务器r420系统安装系统,DELLR420+R720服务器raid+驱动安装教程.docx

热门文章

  1. Latex语法学习05:代码表格的制作
  2. android更改深色模式,安卓微信怎么切换深色模式
  3. 行业陷入“围城”效应,新茶饮品牌凛冬将至
  4. 【剑指offer】19. 二叉树的镜像
  5. 移动鼠标计算鼠标偏移量
  6. R数据分析:竞争风险模型的做法和解释二
  7. android 手机上设置呼叫转移
  8. 网络摄像机内部结构图
  9. 如何使用segy数据绘制地震剖面
  10. 台式计算机用什么电源线,台式电脑电源线接法图解(3分钟学会接电脑电源线)...