一文读懂 Spring Bean 的生命周期,java数据结构面试题及答案整理

  • 首先获取到所有的后置处理器 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 一系列接口)

包括 AspectJWeavingEnablerCustomAutowireConfigurerConfigurationClassPostProcessor 等。这些都是 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 类直接实现接口的方法,比如 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 是一个复合接口,如下:

在这里插入图片描述

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 接口实现类

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

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

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

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

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

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

总结

如果你选择了IT行业并坚定的走下去,这个方向肯定是没有一丝问题的,这是个高薪行业,但是高薪是凭自己的努力学习获取来的,这次我把P8大佬用过的一些学习笔记(pdf)都整理在本文中了

《Java中高级核心知识全面解析》

小米商场项目实战,别再担心面试没有实战项目:

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

战项目、讲解视频,并且后续会持续更新**

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

总结

如果你选择了IT行业并坚定的走下去,这个方向肯定是没有一丝问题的,这是个高薪行业,但是高薪是凭自己的努力学习获取来的,这次我把P8大佬用过的一些学习笔记(pdf)都整理在本文中了

《Java中高级核心知识全面解析》

[外链图片转存中…(img-YZuiXTKr-1712694073400)]

小米商场项目实战,别再担心面试没有实战项目:

[外链图片转存中…(img-fAhYcRHm-1712694073401)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-QzTkgzsI-1712694073401)]

  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值