一文读懂 Spring Bean 的生命周期,unity高级工程师面试题

这篇具有很好参考价值的文章主要介绍了一文读懂 Spring Bean 的生命周期,unity高级工程师面试题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  • 实例化

  • 该对象不再被使用时通过垃圾回收机制进行回收

而对于 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 所指定的方法等,也就对应着上文说的实例化 -> 属性赋值 -> 初始化 -> 销毁四个阶段。

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

3.2 容器级的方法(BeanPostProcessor 一系列接口)

主要是后处理器方法,比如下图的 InstantiationAwareBeanPostProcessorBeanPostProcessor 接口方法。这些接口的实现类是独立于 Bean 的,并且会注册到 Spring 容器中。在 Spring 容器创建任何 Bean 的时候,这些后处理器都会发生作用。

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

3.2.1 InstantiationAwareBeanPostProcessor 源码分析

我们翻一下源码发现 InstantiationAwareBeanPostProcessor 是继承了 BeanPostProcessor

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

  • InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 调用点

Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)

返回值:如果返回的不为null,那么后续的Bean的创建流程【实例化、初始化afterProperties】都不会执行,而是直接使用返回的快捷Bean,此时的正常执行顺序如下:

InstantiationAwareBeanPostProcessor接口中的postProcessBeforeInstantiation,在实例化之前调用。

BeanPostProcessor接口中的postProcessAfterInitialization,在实例化之后调用。

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

总之,postProcessBeforeInstantiation 在 doCreateBean 之前调用,也就是在 bean 实例化之前调用的,英文源码注释解释道该方法的返回值会替换原本的 Bean 作为代理,这也是 AOP 等功能实现的关键点。

  • InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation 调用点

boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException

正常情况下在实例化之后在执行populateBean之前调用

返回值:如果有指定的bean的时候返回false,那么后续的属性填充和属性依赖注入【populateBean】将不会执行,同时后续的postProcessPropertyValues将不会执行,但是初始化和BeanPostProcessor的仍然会执行。

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)

实例化之后调用,在方法applyPropertyValues【属性填充】之前

返回值:如果返回null,那么将不会进行后续的属性填充,比如依赖注入等,如果返回的pvs额外的添加了属性,那么后续会填充到该类对应的属性中。

pvs:PropertyValues对象,用于封装指定类的对象,简单来说就是PropertyValue的集合,里面相当于以key-value形式存放类的属性和值。

pds:PropertyDescriptor对象数组,PropertyDescriptor相当于存储类的属性,不过可以调用set,get方法设置和获取对应属性的值。

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

3.2.2 BeanPostProcessor 源码分析

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

进入初始化接口:

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

我们先来看

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

  • 首先获取到所有的后置处理器 getBeanPostProcessors()

  • 在 for 循环中依次调用后置处理器的方法 processor.postProcessBeforeInitialization(result, beanName);

  • 进入 postProcessBeforeInitialization 方法

org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

进入 invokeAwareInterfaces(bean); 方法,当前 bean 实现了 ApplicationContextAware 接口。

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

  • ApplicationContextAwareProcessor#postProcessBeforeInitialization 首先判断此 bean 是不是各种的Aware,如果是它列举的那几个 Aware 就获取 Bean 工厂的权限,可以向容器中导入相关的上下文环境,目的是为了 Bean 实例能够获取到相关的上下文,如果不是它列举的几个 Aware,那就调用 invokeAwareInterfaces(bean),向容器中添加相关接口的上下文环境。

3.3 工厂后处理器方法(BeanFactoryProcessor 一系列接口)

包括 AspectJWeavingEnablerCustomAutowireConfigurerConfigurationClassPostProcessor 等。这些都是 Spring 框架中已经实现好的 BeanFactoryPostProcessor,用来实现某些特定的功能。

我们知道 Spring IoC 容器初始化的关键环节就在 org.springframework.context.support.AbstractApplicationContext#refresh 方法中 ,容器创建的主体流程都在这个方法里面,这个方法是真的重要!!!

对于工厂后处理器方法老周这里直接带你看 invokeBeanFactoryPostProcessors(beanFactory); 方法,这个方法处理的是 BeanFactoryPostProcessor 接口的 Bean。调用方法如下:

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

跟到最重要的方法里去,代码虽长,但逻辑中规中矩。

BeanFactoryPostProcessor:一切处理 BeanFactory 的父接口

BeanDefinitionRegistryPostProcessor:实现了 BeanFactoryPostProcessor 接口的接口

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

流程说明:

  • 调用 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry(registry) 方法。参数 beanFactoryPostProcessors 传入的优先处理掉。然后获取容器注册的,对于这些 Bean 按照 PriorityOrdered 接口、Ordered、没有排序接口的实例分别进行处理。

  • 调用 BeanFactoryPostProcessor#postProcessBeanFactory(beanFactory) 方法。备注:BeanDefinitionRegistryPostProcessor 属于 BeanFactoryPostProcessor 子接口。先处理属于 BeanDefinitionRegistryPostProcessor 接口实例的 postProcessBeanFactory(beanFactory) 方法,然后获取容器注册的。对于这些 Bean 按照 PriorityOrdered 接口、Ordered、没有排序接口的实例分别进行处理。

3.4 Bean 级生命周期方法

可以理解为 Bean 类直接实现接口的方法,比如 BeanNameAwareBeanFactoryAwareApplicationContextAwareInitializingBeanDisposableBean 等方法,这些方法只对当前 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 是一个复合接口,如下:

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

Aware 调用时机源码分析

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

可以看到并不是所有的 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 生命周期流程图

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

四、常用接口说明


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);

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java
一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java
一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java
一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java
一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java
一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

最后

终极手撕架构师的学习笔记:分布式+微服务+开源框架+性能优化

一文读懂 Spring Bean 的生命周期,unity高级工程师面试题,2024年程序员学习,spring,unity,java

同时减轻大家的负担。**
[外链图片转存中…(img-qNEaDZpK-1711998651454)]
[外链图片转存中…(img-osYT4SQp-1711998651455)]
[外链图片转存中…(img-TgLnRWye-1711998651455)]
[外链图片转存中…(img-dr3jdebo-1711998651455)]
[外链图片转存中…(img-U9nvWeGo-1711998651456)]
[外链图片转存中…(img-yclFrYGC-1711998651456)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-RXCOSKxA-1711998651456)]

最后

终极手撕架构师的学习笔记:分布式+微服务+开源框架+性能优化

[外链图片转存中…(img-I6Z5paun-1711998651457)]文章来源地址https://www.toymoban.com/news/detail-845887.html

到了这里,关于一文读懂 Spring Bean 的生命周期,unity高级工程师面试题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【spring】spring bean的生命周期

    spring bean的生命周期 简介 本文测试并且介绍了spring中bean的生命周期,如果只想知道结果可以跳到最后一部分直接查看。 一、bean的创建阶段 spring中的bean是何时创建的? 在spring中有一个非常重要的注解,叫做**@Scope**,这个注解是用来控制spring中的bean是否是单例的,一般情况

    2024年02月15日
    浏览(35)
  • Spring Bean的生命周期

    Bean生命周期的整个执行过程描述如下: 1、根据配置情况调用Bean构造方法或工厂方法实例化 Bean。 2、利用依赖注入完成Bean中所有属性值的配置注入。 3、如果Bean 实现了BeanNameAware 接口,则 Spring调用Bean的setBeanName()方法传入当前Bean的id值。 4、如果Bean实现了BeanFactoryAware 接口

    2023年04月22日
    浏览(52)
  • Spring -- Bean的生命周期

    Spring容器在进行实例化时,会将xml配置的bean的信息封装成一个BeanDefinition对象,Spring根据BeanDefinition来创建Bean对象,里面有很多的属性用来描述Bean   BeanDefinition 中几个重要方法如下 beanClassName:bean 的类名 initMethodName:初始化方法名称 properryValues:bean 的属性值 scope:作用域

    2024年02月15日
    浏览(39)
  • 【Spring】Spring的Bean的生命周期

    作者简介:大家好,我是五度鱼,一个普通的Java领域博主,不停输出Java技术博客和干货 。 座右铭:锲而不舍,金石可镂 。 个人主页:五度鱼学Java的主页 在 Java 中, Bean 是一个重要的概念,它代表了应用程序中的一个对象。在开发中,我们经常使用 Bean 来管理对象的生命

    2024年01月16日
    浏览(40)
  • Spring整理-Spring Bean的生命周期

    Spring Bean的生命周期涉及多个阶段,从Bean的定义到其销毁。在这个过程中,Spring容器负责创建、初始化、使用和最终销毁Bean。了解这个生命周期有助于更好地管理Bean的行为和资源使用。 实例化(Instantiation): 容器首先创建Bean的实例。 填充属性(Populate Properties): 容器

    2024年01月21日
    浏览(36)
  • Spring(11) Bean的生命周期

    首先,为什么要学习 Spring 中 Bean 的生命周期呢? 虽然不了解 Bean 的生命周期,并不影响日常工作中的开发。但是如果我们了解了 Bean 的生命周期,可以帮助我们更好地掌握 Spring 框架,并且能够让我们更好地去理解 Spring 容器是如何管理和创建 Bean 示例的。如果以后遇到 B

    2024年02月14日
    浏览(27)
  • Spring源码:Bean生命周期(三)

    在之前的文章中,我们已经对 bean 的准备工作进行了讲解,包括 bean 定义和 FactoryBean 判断等。在这个基础上,我们可以更加深入地理解 getBean 方法的实现逻辑,并在后续的学习中更好地掌握 createBean 方法的实现细节。 讲解getBean方法之前,我们先来看看他有几种常见的用法:

    2024年02月02日
    浏览(35)
  • Spring中 Bean的生命周期

    如果把Spring看做一个大型工厂,则Spring容器中的Bean就是该工厂的产品。要想使用这个工厂生产和管理Bean,就需要在配置文件中告诉它需要哪些Bean,以及需要使用何种方式将这些Bean装配到一起。 Bean的本质就是Java中的类,而Spring中的Bean其实就是对实体类的引用,来生产Java类

    2024年01月24日
    浏览(29)
  • Spring Bean的生命周期解读

    目录   1. Spring IOC容器 1.1 Spring IOC 容器的设计 1.1.1 BeanFactory 1.1.2 ApplicationContext 1.2 Spring Bean的生命周期 1.2.1 BeanDefinition 1.2.2 InstantiationAwareBeanPostProcessor和BeanPostProcessor 1.2.3 测试生命周期   Spring IOC 容器的设计主要是基于 BeanFactory 和 ApplicationContex t两个接口,其中ApplicationConte

    2024年02月11日
    浏览(30)
  • 详解Spring Bean的生命周期

    Spring Bean的生命周期包括以下阶段: 1. 实例化Bean 对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。 对于ApplicationContext容器,当容器启动结束后,便实例化所有的bean。

    2024年02月14日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包