[版权申明] 非商业目的注明出处可自由转载
出自:shusheng007

文章目录

  • 概述
  • Bean的生命周期
    • 感受Bean生命周期
    • 具体说明
  • 扩展点
    • 容器级扩展点
    • 对象级扩展点
  • 多一点
  • 总结

概述

IOC与AOP是Spring框架最重要的两个思想。其中的IOC使得我们可以将对象及其依赖交由Spring容器来管理,极大的解放了我们的生产力。但凡事都有两面性,我们在逃避义务的同时也就意味着放弃了控制的权利,以前对象和依赖都是由我们负责处理,我们想怎么弄就怎么弄,但现在交给了spring这个大兄弟,我们做了甩手掌柜,那我们就失去了控制的权利。幸好Spring这个大兄弟比较厚道,给我们留下了若干个扩展点,这些扩展点就是它给我们干预被托管对象的机会,所以我们一定要抓住。

这块经过广大码农兄弟们不懈的内卷已经产生了非常多特别靠谱的资料,各种源码解析一大堆了,可惜就是太绕,这篇文章也只是我自己梳理这个过程留下的笔记,不构成教学资料,不喜勿喷…

Bean的生命周期

你有没有想过在我们日常开发过程中,给类加个@Componet然后用的时候来一个@Autowired就搞定了,这背后发生了什么?总的来说呢就是你在启动App的时候Spring大兄弟先把这些被@Componet的类给生成对象保存起来,然后你使用@Autowired召唤的时候它就还给你。

咱今天看下Spring大兄弟是怎么把这些类给生成对象的,在不需要这些对象的时候是怎么给处理掉的,以及在这个过程中给我们提供了哪些观察和干预这个过程的机会。如果它不给我们干预的机会那就麻烦了,假如你有个需求:

程序员:hi,Spring大兄弟,我想在这个对象属性设置完成后打一句日志,你看行吗?
Spring:不好意思呀,俺不支持,你能不能自己想想办法…
程序员:我R…

首先,Spring大兄弟先把扫描到的要生成对象的类都给包装成BeanDefinition,然后保存到BeanDefinitionRegistry中,用的时候就从这个registry里面取。

感受Bean生命周期

让我们先来感受一下Bean的生命周期以及扩展点吧,学习这些开源框架一个非常好的思路为:会用–学习内部实现方式–善用–改进内部实现方式–提交PullRequest,大部分时候我们都止于第一步…

我写了一个实现各种Bean级别的扩展点的类,以及两个实现容器级别的扩展点的类,然后运行,查看日志。

  • Programmer类实现了各种常用的Bean级别的扩展点
//@Component
public class Programmer implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {private JavaLang javaLang;public Programmer() {System.out.println("1.调用构造函数");}//    @Autowiredpublic void setJavaLang(JavaLang javaLang) {System.out.println("2.调用属性赋值方法:" + javaLang.getClass().getCanonicalName());this.javaLang = javaLang;}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {System.out.println("4.调用BeanFactoryAware扩展:" + beanFactory.getClass().getCanonicalName());}@Overridepublic void setBeanName(String name) {System.out.println("3.调用BeanNameAware扩展:" + name);}@Overridepublic void destroy() throws Exception {System.out.println("9.调用DisposableBean扩展");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("7.调用InitializingBean扩展");}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {System.out.println("5.调用ApplicationContextAware扩展:" + applicationContext.getClass().getCanonicalName());}@PostConstructpublic void myInit(){System.out.println("6.调用@PostConstruct注解的方法");}@PreDestroypublic void myDestroy(){System.out.println("8.调用@PreDestroy注解的方法");}//在@Bean里使用public void myInit2(){System.out.println("调用@Bean initMethod方法");}//在@Bean里使用public void myDestroy2(){System.out.println("调用@Bean destroyMethod方法");}}
  • 下面两个类实现了容器级别的扩展点InstantiationAwareBeanPostProcessorBeanPostProcessor
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if ("programmer".equals(beanName)) {System.out.println("调用 BeanPostProcessor.postProcessBeforeInitialization() 方法,bean:" +bean.getClass().getCanonicalName());}return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if ("programmer".equals(beanName)) {System.out.println("调用 BeanPostProcessor.postProcessAfterInitialization() 方法,bean:" +bean.getClass().getCanonicalName());}return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);}
}@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {if ("programmer".equals(beanName)) {System.out.println("调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 方法,bean:" +beanClass.getCanonicalName());}return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName);}@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {if ("programmer".equals(beanName)) {System.out.println("调用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法,bean:" +bean.getClass().getCanonicalName());}return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);}@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {if ("programmer".equals(beanName)) {System.out.println("调用 InstantiationAwareBeanPostProcessor.postProcessProperties() 方法,bean:" +bean.getClass().getCanonicalName() +" values:" + Arrays.toString(pvs.getPropertyValues()));}return InstantiationAwareBeanPostProcessor.super.postProcessProperties(pvs, bean, beanName);}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if ("programmer".equals(beanName)) {System.out.println("调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInitialization() 方法,bean:" +bean.getClass().getCanonicalName());}return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if ("programmer".equals(beanName)) {System.out.println("调用 InstantiationAwareBeanPostProcessor.postProcessAfterInitialization() 方法,bean:" +bean.getClass().getCanonicalName());}return InstantiationAwareBeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);}
}
  • Config文件

生成Programmer的Bean

@Configuration
public class LifecycleConfig {@Bean(name = "programmer", initMethod = "myInit2", destroyMethod = "myDestroy2")public Programmer programmer() {Programmer programmer = new Programmer();// 使用这句直接设置属性的代码,无法测试出spring bean 注入属性的那个步骤programmer.setJavaLang(new JavaLang());return programmer;}
}

值得注意的是,直接调用设置对象属性的方法不能展现出spring设置属性的生命周期。 这块可以使用@Componet以及使用@Autowired的方式注入属性。 这里主要是为了调用@Bean里的初始化与销毁的方法。

  • 测试调用:

可以在close前面打断点观察

@SpringBootApplication
public class MvcInspectApplication {public static void main(String[] args) {ConfigurableApplicationContext applicationContext = SpringApplication.run(MvcInspectApplication.class, args);Programmer programmer = (Programmer) applicationContext.getBean("programmer");applicationContext.close();}
}

输出:

调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
1.调用构造函数
调用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
调用 InstantiationAwareBeanPostProcessor.postProcessProperties() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer values:[]
2.调用属性赋值方法:top.shusheng007.mvcinspect.beanlifecycle.JavaLang
3.调用BeanNameAware扩展:programmer
4.调用BeanFactoryAware扩展:org.springframework.beans.factory.support.DefaultListableBeanFactory
5.调用ApplicationContextAware扩展:org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
调用 BeanPostProcessor.postProcessBeforeInitialization() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInitialization() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
6.调用@PostConstruct注解的方法
7.调用InitializingBean扩展
调用@Bean initMethod方法
调用 BeanPostProcessor.postProcessAfterInitialization() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
调用 InstantiationAwareBeanPostProcessor.postProcessAfterInitialization() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
8.调用@PreDestroy注解的方法
9.调用DisposableBean扩展
调用@Bean destroyMethod方法

具体说明

从输出已经可以看到这些扩展点的执行顺序了,其中混杂这两个容器级别的扩展点的输出。

Bean的生命周期可以大体分为下面四个步骤,上面的输出都可以归纳进这四个步骤中

  • 实例化 Instantiation

根据BeanDefinition通过反射来创建类的实例

调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
1.调用构造函数
调用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
调用 InstantiationAwareBeanPostProcessor.postProcessProperties() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer values:[]

可见InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()在对象实例化之前被执行了。开那个类的名称前缀`InstantiationAware,一看就知道是感受对象实例化过程的。

  • 属性赋值 Populate

给生成的对象设置属性,例如你经常使用的@Autowired,@Value什么的来设置类的属性。

2.调用属性赋值方法:top.shusheng007.mvcinspect.beanlifecycle.JavaLang
  • 初始化 Initialization

处理各种Aware接口回调,例如BeanNameAware,以及那些初始化的方法,例如使用@PostConstruct注解的方法,以及在@Bean里面指定的初始化方法等。

3.调用BeanNameAware扩展:programmer
4.调用BeanFactoryAware扩展:org.springframework.beans.factory.support.DefaultListableBeanFactory
5.调用ApplicationContextAware扩展:org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
调用 BeanPostProcessor.postProcessBeforeInitialization() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInitialization() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
6.调用@PostConstruct注解的方法
7.调用InitializingBean扩展
调用@Bean initMethod方法
调用 BeanPostProcessor.postProcessAfterInitialization() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
调用 InstantiationAwareBeanPostProcessor.postProcessAfterInitialization() 方法,bean:top.shusheng007.mvcinspect.beanlifecycle.Programmer
  • 销毁 Destruction

调用使用@PreDestroy注解的方法,以及DisposableBean接口的回调,还有在@Bean里面指定的销毁方法等

8.调用@PreDestroy注解的方法
9.调用DisposableBean扩展
调用@Bean destroyMethod方法

整个Bean的产生逻辑中,前3个阶段的代码在AbstractAutowireCapableBeanFactory类的doCreateBean方法里,可自行查看。

可能是我水平不够吧,亦或者是框架比较复杂,我读的时间又比较短,看Spring的源码感觉真的是好乱啊,要想摸清楚,你还是要自己打断点跟一下,不过可能跟着跟着就跑偏了…

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactoryimplements AutowireCapableBeanFactory{protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException{// Instantiate the bean.//第一步:实例化 InstantiationBeanWrapper instanceWrapper = null;if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}...// Initialize the bean instance.Object exposedObject = bean;try {//第二步:属性赋值 PopulatepopulateBean(beanName, mbd, instanceWrapper);//第三步:初始化 InitializationexposedObject = initializeBean(beanName, exposedObject, mbd);}}
}

第四个销毁的阶段在AbstractApplicationContextdoClose方法里

public abstract class AbstractApplicationContext extends DefaultResourceLoaderimplements ConfigurableApplicationContext {// 第四步:销毁 Destruction    protected void doClose(){}
}

上面就是Spring Bean 的生命周期概述了,其实这个生命周期4个阶段知道大概就行,我们特别关心的其实是Spring大兄弟给我们的各种扩展点,因为我们真的要用他们来写程序,不知道就没法写…下面让我们大概看一下

扩展点

所谓Bean生命周期的扩展点,就是Spring留给我们干预Bean生命周期的回调。这个比较好理解,因为我们把对象及其依赖的管理托管给了Spring,但是我们又要在这个过程中进行干预,所以spring就必须在管理Bean的各个阶段不断的询问我们:

hello: 死码农,现在俺正在对象的实例化阶段,你有什么要处理的吗?
hi: 屌丝,现在刚刚给对象设置完属性,你有什么要处理的吗?
哎:攻城狮,现在我要销毁对象拉,你丫有什么要处理的吗?
喂:那个谁,现在…,你要…?

扩展点分为容器级与对象级,如果是容器级的话你实现的那个扩展点操作会应用到容器内所有的Bean,如果是Bean级别的话就只能影响那个Bean。

容器级扩展点

容器级扩展点作用于整个容器,对容器内的bean都起作用

  • BeanPostProcessor
  • InstantiationAwareBeanPostProcessor

下面这张图是我从这里一文读懂 Spring Bean 的生命周期致敬的…。

图中展示了两个容器级别的扩展点在Bean生命周期的回调点。其实那几个回调方法的名称已经非常好的说明了他们执行的时机,在Bean实例化的前后,以及在bean初始化的前后都有回调点。

对象级扩展点

对象级扩展点作用于单个bean,只对单个bean起作用

  • BeanNameAware
  • BeanClassLoaderAware
  • BeanFactoryAware
  • EnvironmentAware
  • EmbeddedValueResolverAware
  • ApplicationContextAware

多一点

你想过SpringBoot程序启动后是怎么一路执行的吗?不怕你笑话,我以前想过,但没想明白,这肯定想不明白啊,得看…

  • 入口

SpringApplication类的静态run方法

@SpringBootApplication
public class MvcInspectApplication {public static void main(String[] args) {SpringApplication.run(MvcInspectApplication.class, args);}
}
  • 具体执行方法

SpringApplication类的

public ConfigurableApplicationContext run(String... args) {//打印Spring的标志Banner printedBanner = printBanner(environment);//开始处理Bean的流程refreshContext(context);
}
  • AbstractApplicationContext

refreshContext(context); 调用到了AbstractApplicationContextrefresh方法,老重要了…

public void refresh() throws BeansException, IllegalStateException {// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);
}

finishBeanFactoryInitialization(beanFactory); 这个方法就是处理Bean的入口。

  • AbstractAutowireCapableBeanFactory
 protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException{// Instantiate the bean.//第一步:实例化 InstantiationBeanWrapper instanceWrapper = null;if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}...// Initialize the bean instance.Object exposedObject = bean;try {//第二步:属性赋值 PopulatepopulateBean(beanName, mbd, instanceWrapper);//第三步:初始化 InitializationexposedObject = initializeBean(beanName, exposedObject, mbd);}}

总结

读完本文至少要明白,扩展点分两类,Bean生命周期分4步,几个关键扩展点执行时机。

一如既往的你可以从GitHub上获得源码 mvc-inspect

好文推荐:

请别再问Spring Bean的生命周期了!

秒懂SpringBoot之Spring对象生命周期与扩展点浅尝辄止相关推荐

  1. Spring.NET学习笔记(5)-对象生命周期和创建者对象

    一.对象生命周期 说白了就是一init初始化方法和Dispose方法 两种实现方式 1.实现接口方法(造成耦合,放弃),IInitializingObject / init-method和IDispo ...

  2. Spring IoC容器与Bean管理18:Bean对象的作用域及生命周期三:对象生命周期;

    说明: (1)本篇博客主要根据案例阐述对象的声明周期: (2)其中,比较重要的是注意下这个对应关系: (3)还有就是调用[registerShutdownHook()]销毁IoC容器: 目录 一:be ...

  3. Spring Bean生命周期: Bean的实例化

    [Spring Bean 生命周期系列]传送门 1.Spring Bean生命周期: Bean元信息的配置与解析阶段 2.Spring Bean生命周期: Bean的注册 3.Spring Bean生 ...

  4. Spring Bean生命周期:Bean的初始化阶段

    [Spring Bean 生命周期系列]传送门 1.Spring Bean生命周期: Bean元信息的配置与解析阶段 2.Spring Bean生命周期: Bean的注册 3.Spring Bean生 ...

  5. 容器,对象生命周期管理的基石

    2019独角兽企业重金招聘Python工程师标准>>> 郑重申明:包括本文在内的很多技术文章,大多出自山外高人,而非Fans. Fans暂时没有能力写作优秀的技术文章,Fans只是转 ...

  6. Spring5源码 - 07 Spring Bean 生命周期流程 源码解读02

    文章目录 Pre 通俗流程 finishBeanFactoryInitialization Pre Spring5源码 - 06 Spring Bean 生命周期流程 概述 01 接上文 通俗流程 下 ...

  7. spring bean生命周期_Spring中bean的生命周期和扩展点有哪些?

    前言 今天和大家分享一下Spring中Bean的生命周期的一些知识.先来说一下什么是生命周期吧,生命周期从其语义上理解就是一个对象从产生到销毁的整个过程,之所以把这个过程称为生命周期是因为其就像一个生 ...

  8. Spring Bean生命周期过程

    Spring Bean生命周期过程 Spring Bean生命周期指的是Bean加载Spring容器的过程,单例的Bean与多例的Bean加载过程是不一样的.这里指的是单例Bean的加载过程. 图:S ...

  9. Spring Bean 生命周期之“我从哪里来”?懂得这个很重要

    Spring bean 的生命周期很容易理解.实例化 bean 时,可能需要执行一些初始化以使其进入可用 (Ready for Use)状态.类似地,当不再需要 bean 并将其从容器中移除时,可能需 ...

最新文章

  1. 【jquery】用jsp写jquery的模板
  2. 推荐一个你最喜欢的辅助办公软件,你会推荐什么?
  3. vim 分屏 最大化_5分钟学会Vim分屏操作方方面面
  4. python如何对人数向上取整_python中的向上取整向下取整以及四舍五入的方法
  5. c++模板类静态成员变量_一文讲透父子类中静态变量,成员变量初始化顺序原理...
  6. jQuery的实现原理
  7. Linux学习总结(20)——Linux 文件夹结构和作用
  8. Java Web学习总结(3)——Servlet详解
  9. Hadoop1.x HDFS系统架构
  10. 浅谈我对 jQuery 的了解
  11. [Giveaway] 来自AnyBizSoft、4Media、EASEUS的限时免费软件
  12. 批处理之for /r
  13. c语言line函数编写画六边形,canvas 画六边形
  14. 三极管与恒流源充放电电路
  15. 【Codeforces Round #439 (Div. 2) A】The Artful Expedient
  16. C语言 01背包问题
  17. Java课设对对碰_java 对对碰游戏
  18. 西南交大研究生英语读写译慕课答案
  19. java实现录屏_Android5.0以上版本录屏实现代码(完整代码)
  20. java中的key,继续谈谈java中的Key

热门文章

  1. 公司 邮件 翻译 培训 长难句 13
  2. how-I-hacked-Facebook-again-unauthenticated-RCE-on-MobileIron-MDM笔记
  3. 疯狂的程序员-第二十三章
  4. Libre密聊——致力于私密聊天的用心APP
  5. laravel集成谷歌验证_如何将Google的两因素身份验证添加到Laravel
  6. 云和恩墨进入基础软件厂商成长象限 未来发展潜力无限
  7. 机械工程基础笔记整理
  8. php 获取rsa 模数,使用Python从公钥获取RSA指数和模数
  9. python可视化分析网易云音乐评论_Python数据可视化:网易云音乐歌单
  10. jQuery的排他思想