如果你每次面试前都要去背一篇Spring中Bean的生命周期,请看完这篇文章_Java笔记虾的博客-程序员宅基地

技术标签: spring  java  aop  编程语言  ioc  

前言

当你准备去复习Spring中Bean的生命周期的时候,这个时候你开始上网找资料,很大概率会看到下面这张图:


先不论这张图上是否全面,但是就说这张图吧,你是不是背了又忘,忘了又背?

究其原因在于,你没有理解为什么需要这些步骤,也不知道为什么要按这个顺序执行

笔者在阅读完整个IOCAOP的源码后,希望通过这篇文章讲一讲我的Spring中Bean生命周期的看法,帮助大家能理解性的记忆整个流程,而不是死记硬背!

基础知识补充

所谓理解也是建立在有一定知识储备的基础上的,所以这里先补充一些基础概念

Bean创建的三个阶段

Spring在创建一个Bean时是分为三个步骤的

  • 实例化,可以理解为new一个对象

  • 属性注入,可以理解为调用setter方法完成属性注入

  • 初始化,你可以按照Spring的规则配置一些初始化的方法(例如,@PostConstruct注解)

生命周期的概念

Bean的生命周期指的就是在上面三个步骤中后置处理器BeanPostprocessor穿插执行的过程

后置处理器的分析

按照实现接口进行分类

  1. 直接实现了BeanPostProcessor接口

最简单的后置处理器,也就是说直接实现了BeanPostProcessor接口,这种后置处理器只能在初始化前后执行

public interface BeanPostProcessor {
    
 // 初始化前执行的方法
 @Nullable
 default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  return bean;
 }    
    
 // 初始化后执行的方法
 default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  return bean;
 }

}
  1. 直接实现了InstantiationAwareBeanPostProcessor接口

在第一种后置处理的基础上进行了一层扩展,可以在Bean的实例化阶段前后执行

// 继承了BeanPostProcessor,额外提供了两个方法用于在实例化前后的阶段执行
// 因为实例化后紧接着就要进行属性注入,所以这个接口中还提供了一个属性注入的方法
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
 
    // 实例化前执行
 default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
  return null;
 }
 
    // 实例化后置
 default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
  return true;
 }
    
    // 属性注入
    default PropertyValues postProcessPropertyValues(
        PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {

        return pvs;
    }
}
  1. Spring内部专用的后置处理器

可能有的小伙伴认为,第三种后置处理器肯定就是用来在属性注入前后执行了的吧。我只能说,大兄弟,太天真了,看看下面这张图


这种情况下再为属性注入阶段专门提供两个方法是不是有点多余呢?实际上第三种后置处理器是Spring为了自己使用而专门设计的

public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
 
    // 推测bean的类型,例如在属性注入阶段我们就需要知道符合依赖类型的Bean有哪些
    @Nullable
    default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
        return null;
    }
 
    // 推断出所有符合要求的构造函数,在实例化对象的时候我们就需要明确到底使用哪个构造函数
    @Nullable
    default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
        throws BeansException {

        return null;
    }
 
    // 获取一个提前暴露的对象,用于解决循环依赖
    default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
        return bean;
    }

}

一般我们在探究生命周期的时候都不会考虑这种后置处理器的执行

生命周期详细介绍

在了解了上面的概念后,我们再来看看这张图


至少现在这张图上缺少了实例化前后后置处理器的执行流程,对吧?

再补充上这一点之后,我们再来看看,属性注入后紧接着已经是初始化的阶段,在初始化阶段开始前应该要调用BeanPostProcessor的预初始化方法(postProcessBeforeInitialization),然后调用自定义的初始化方法,最后调用postProcessAfterInitialization,这是没有问题,但是为什么要在初始前还要调用Aware接口的方法,如果你看了源码的话可能会说,源码就是这么写的,别人就是这么设计的,但是为什么要这么设计呢?我们看源码到一定阶段后不应该仅仅停留在是什么的阶段,而应该多思考为什么,这样能帮助你更好的了解这个框架

那么为什么Aware接口非要在初始化前执行呢?

这样做的目的是因为,初始化可能会依赖Aware接口提供的状态,例如下面这个例子

@Component
public class A implements InitializingBean, ApplicationContextAware {

    ApplicationContext applicationContext;

    @Override
    public void afterPropertiesSet() throws Exception {
        // 初始化方法需要用到ApplicationContextAware提供的ApplicationContext
        System.out.println(applicationContext);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

这种情况下Aware接口当然要在初始化前执行啦!

另外,在讨论Bean的初始化的时候经常会碰到下面这个问题,@PostConstruct,afterPropertiesSet跟XML中配置的init-method方法的执行顺序。

请注意,@PostConstruct实际上是在postProcessBeforeInitialization方法中处理的,严格来说它不属于初始化阶段调用的方法,所以这个方法是最先调用的

其次我们思考下是调用afterPropertiesSet方法的开销大还是执行配置文件中指定名称的初始化方法开销大呢?我们不妨用伪代码演示下

// afterPropertiesSet,强转后直接调用
((InitializingBean) bean).afterPropertiesSet()
    
// 反射调用init-method方法
// 第一步:找到这个方法
Method method = class.getMethod(methodName)
// 第二步:反射调用这个方法
method.invoke(bean,null)

相比而言肯定是第一种的效率高于第二种,一个只是做了一次方法调用,而另外一个要调用两次反射。

因此,afterPropertiesSet的优先级高于XML配置的方式

所以,这三个方法的执行顺序为:

  1. @PostConstruct注解标注的方法

  2. 实现了InitializingBean接口后复写的afterPropertiesSet方法

  3. XML中自定义的初始化方法

在完成初始化,没什么好说的了,最后调用一下postProcessAfterInitialization,整个Bean的生命周期到此结束

总结

本文的主要目的是想要帮助大家更好的理解整个Bean的生命周期,不过理解是建立在有一定知识存储的基础上的

你至少要对Bean的后置处理器跟Bean创建有一个大概的理解,那么通过本文你能理清一些细节方面的东西

例如,为什么Aware接口执行在初始化阶段之前?为什么初始化的三个方法会按

@PostConstructafterPropertiesSet,XML中定义的初始化方法这个顺序执行。

精彩推荐
一百期Java面试题汇总SpringBoot内容聚合IntelliJ IDEA内容聚合Mybatis内容聚合

欢迎长按下图关注公众号后端技术精选

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_38405253/article/details/107625066

智能推荐

RealSense D435i下运行开源双目SLAM_d435是双目吗_TYINY的博客-程序员宅基地

转载自:https://blog.csdn.net/qq_39266065/article/details/108275010RealSense D435i下运行开源双目SLAM秃头队长 2020-08-28 15:24:23 604 收藏 6 分类专栏: SLAM版权一丶ORB SLAM2参考README文件Add the path including Examples/ROS/ORB_SLAM2 to the ROS_PACKAGE_PATH environment var

基于SSH三大框架的员工管理系统——总结_基于ssh的管理系统心得_magi617的博客-程序员宅基地

基于SSH三大框架的员工管理系统,系统角色包括普通用户和管理员两种,首页有管理员登录入口链接。系统功能主要包括管理员对用户的基本增、删、改、查和分页显示用户信息等。

100度小例子_Vivian_shuang的博客-程序员宅基地

DOCTYPE html>html lang="en">head>meta charset="UTF-8">title>精灵图title>link rel="stylesheet" href="css/reset.css">style>.father{width:980px;margin:0 auto;}p{padding:0;

list.stream.map的使用_list stream map_JavaGirl_亚兰的博客-程序员宅基地

抽取对象中所有id的集合List&lt;String&gt; idList = ObjectList.stream.map(Object::getId).collect(Collectors.toList());

随便推点

rxjava : Completable # andThen_Mars-xq的博客-程序员宅基地

Completable # andThen() 源码:先订阅Completable,再订阅 ObservableSource 、 Publisher 、 SingleSource 、 MaybeSource 、 CompletableSource ,并返回新的Observable、Flowable、Single、Maybe、Completable来自此Completable的【错误事...

Vue Day 03课堂回顾_星光兔的博客-程序员宅基地

一.组件化开发1.1. 父子组件的访问children/refsparent/root1.2. slot的使用基本使用具名插槽编译的作用域作用域插槽二. 前端模块化2.1. 为什么要使用模块化简单写js代码带来的问题闭包引起代码不可复用自己实现了简单的模块化AMD/CMD/CommonJS2.2. ES6中模块化的使用exportimport三.webpack3.1. 什么是webpackwebpack和gulp对比webpack依赖环境安装we

百度地图迁徙大数据_百度地图大数据:五一高速拥堵不似预期,广深成热门迁出入地..._weixin_39726131的博客-程序员宅基地

五一假期在即,你是否做好了“出行功课”?高速拥堵水平降低、公众出门不出城、公园成踏青赏景热门目的地……在全国疫情防控仍未松懈的时刻,2020年的五一或许注定与往年不同。近日,百度地图发布2020五一假期安全出行大数据,显示今年节日期间全国高速拥堵情况有所缓解,但节前节后反高于去年同期。广东省内方面,广州、深圳同时上榜节前全国热门迁入、迁出地,但出行强度总体有所下降。广州深圳同时上榜热门迁入、迁出地...

TensorFlow学习之LSTM+CNN用于NLP文本分类(附源码及数据集)_tensorflow文本分析_鹿鸣Llane的博客-程序员宅基地

一直想做一个多个网络融合的模型,最近学习了一个使用LSTM联合CNN用于单标签文本分类的项目,在这里做个笔记。侵删。原项目GitHub地址:https://github.com/NLPxiaoxu/Easy_Lstm_Cnn训练所用数据集:https://pan.baidu.com/s/1daGvDO4UBE5NVrcLaCGeqA 提取码: 9x3i数据集本项目的主题是单标签文本分类,具...

手机安装Charles证书后,抓取的请求依然为unknown(已解决)_测试小菜鸟_Grious的博客-程序员宅基地

问题:下载安装好证书后,请求依然如下图:解决办法:Proxy-&amp;gt;SSL Proxying Settings   进行如下设置:     

推荐文章

热门文章

相关标签