当前位置:首页 > 通信资讯 > 正文

spring bean生命周期 面试(spring的生命周期面试题)

spring bean生命周期 面试(spring的生命周期面试题)

Spring作为当前Java最流行、最强大的轻量级框架。Spring Bean的生命周期也是面试高频题,了解Spring Bean周期也能更好地帮助我们解决日常开发中的问题。程序员应该都知道Spring的基础容器是ApplicationContext。应很多粉丝的强烈建议,本文我来分析分析 ApplicationContext中Bean的生命周期。ApplicationContext是顶层容器接口BeanFactory的实现类,因此,我们了解了ApplicationContext的生命周期逻辑,也基本上了解了其他类型容器的生命周期逻辑。

一、Spring生命周期流程图

下面先来看一张Spring Bean完整的生命周期流程图,下图描述的是从Spring容器初始化Bean开始直到Spring容器销毁Bean,所经历的关键节点。

spring bean生命周期 面试(spring的生命周期面试题)

从上图可以看出,Spring Bean的生命周期管理的基本思路是:在Bean出现之前,先准备操作Bean的BeanFactory,然后操作完Bean,所有的Bean也还会交给BeanFactory进行管理。在所有Bean操作准备BeanPostProcessor作为回调。在Bean的完整生命周期管理过程中,经历了以下主要几个步骤:

1.1 Bean创建前的准备阶段

步骤1:Bean容器在配置文件中找到Spring Bean的定义以及相关的配置,如init-method和destroy-method指定的方法。步骤2:实例化回调相关的后置处理器如BeanFactoryPostProcessor、BeanPostProcessor、InstantiationAwareBeanPostProcessor等

1.2 创建Bean的实例

步骤3:Srping 容器使用Java反射API创建Bean的实例。步骤4:扫描Bean声明的属性并解析。

1.3 开始依赖注入

步骤5:开始依赖注入,解析所有需要赋值的属性并赋值。步骤6:如果Bean类实现BeanNameAware接口,则将通过传递Bean的名称来调用setBeanName()方法。步骤7:如果Bean类实现BeanFactoryAware接口,则将通过传递BeanFactory对象的实例来调用setBeanFactory()方法。步骤8:如果有任何与BeanFactory关联的BeanPostProcessors对象已加载Bean,则将在设置Bean属性之前调用postProcessBeforeInitialization()方法。步骤9:如果Bean类实现了InitializingBean接口,则在设置了配置文件中定义的所有Bean属性后,将调用afterPropertiesSet()方法。

1.4 缓存到Spring容器

步骤10:如果配置文件中的Bean定义包含init-method属性,则该属性的值将解析为Bean类中的方法名称,并将调用该方法。步骤11:如果为Bean Factory对象附加了任何Bean 后置处理器,则将调用postProcessAfterInitialization()方法。

1.5 销毁Bean的实例

步骤12:如果Bean类实现DisposableBean接口,则当Application不再需要Bean引用时,将调用destroy()方法。步骤13:如果配置文件中的Bean定义包含destroy-method属性,那么将调用Bean类中的相应方法定义。

二、代码实战演示

下面我们用一个简单的Bean来演示并观察一下Spring Bean完整的生命周期。

2.1 准备Author类

1、首先是一个简单的Bean,调用Bean自身的方法和Bean级生命周期接口方法,为了方便演示,它实现了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这4个接口,同时添加2个init-method和destory-method方法,对应配置文件中的init-method和destroy-method。具体代码如下:

  1. packagecom.tom.lifecycle;
  2. importlombok.Data;
  3. importlombok.extern.slf4j.Slf4j;
  4. importorg.springframework.beans.BeansException;
  5. importorg.springframework.beans.factory.*;
  6. @Slf4j
  7. @Data
  8. publicclassAuthorimplementsBeanFactoryAware,BeanNameAware,InitializingBean,DisposableBean{
  9. privateStringname;
  10. privateStringaddress;
  11. privateintage;
  12. privateBeanFactorybeanFactory;
  13. privateStringbeanName;
  14. publicAuthor(){
  15. log.info("【构造器】调用Tom类的构造器实例化");
  16. }
  17. publicvoidsetName(Stringname){
  18. log.info("【注入属性】name");
  19. this.name=name;
  20. }
  21. publicvoidsetAddress(Stringaddress){
  22. log.info("【注入属性】address");
  23. this.address=address;
  24. }
  25. publicvoidsetAge(intage){
  26. log.info("【注入属性】age");
  27. this.age=age;
  28. }
  29. //实现BeanFactoryAware接口的方法
  30. publicvoidsetBeanFactory(BeanFactorybeanFactory)throwsBeansException{
  31. log.info("【BeanFactoryAware接口】调用setBeanFactory方法");
  32. this.beanFactory=beanFactory;
  33. }
  34. //实现BeanNameAware接口的方法
  35. publicvoidsetBeanName(StringbeanName){
  36. log.info("【BeanNameAware接口】调用setBeanName方法");
  37. this.beanName=beanName;
  38. }
  39. //实现DiposibleBean接口的方法
  40. publicvoiddestroy()throwsException{
  41. log.info("【DiposibleBean接口】调用destroy方法");
  42. }
  43. //实现InitializingBean接口的方法
  44. publicvoidafterPropertiesSet()throwsException{
  45. log.info("【InitializingBean接口】调用afterPropertiesSet方法");
  46. }
  47. //通过<bean>的init-method属性指定的初始化方法
  48. publicvoidbeanInit(){
  49. log.info("【init-method】调用<bean>的init-method属性指定的初始化方法");
  50. }
  51. //通过<bean>的destroy-method属性指定的初始化方法
  52. publicvoidbeanDestory(){
  53. log.info("【destroy-method】调用<bean>的destroy-method属性指定的初始化方法");
  54. }
  55. }

在配置Spring配置文件中加入如下内容:

  1. <beanid="author"class="com.tom.lifecycle.Author"
  2. init-method="beanInit"
  3. destroy-method="beanDestory"
  4. scope="singleton"
  5. p:name="Tom"p:address="湖南长沙"p:age="18"/>

2.2 演示BeanFactoryPostProcessor的执行

1.创建GPBeanFactoryPostProcessor类,并实现BeanFactoryPostProcessor接口,具体代码如下:

  1. packagecom.tom.lifecycle;
  2. importlombok.extern.slf4j.Slf4j;
  3. importorg.springframework.beans.BeansException;
  4. importorg.springframework.beans.factory.config.BeanDefinition;
  5. importorg.springframework.beans.factory.config.BeanFactoryPostProcessor;
  6. importorg.springframework.beans.factory.config.ConfigurableListableBeanFactory;
  7. @Slf4j
  8. publicclassGPBeanFactoryPostProcessorimplementsBeanFactoryPostProcessor{
  9. publicGPBeanFactoryPostProcessor(){
  10. super();
  11. log.info("调用BeanFactoryPostProcessor实现类构造器!!");
  12. }
  13. publicvoidpostProcessBeanFactory(ConfigurableListableBeanFactoryconfigurableListableBeanFactory)throwsBeansException{
  14. log.info("BeanFactoryPostProcessor调用postProcessBeanFactory方法");
  15. BeanDefinitionbd=configurableListableBeanFactory.getBeanDefinition("author");
  16. bd.getPropertyValues().addPropertyValue("age","16");
  17. }
  18. }

2.在配置Spring配置文件中加入如下内容:

  1. <beanid="beanFactoryPostProcessor"class="com.tom.lifecycle.GPBeanFactoryPostProcessor"/>

3.编写测试类BeanLifeCycleTest,具体代码如下:

  1. packagecom.tom.lifecycle;
  2. importlombok.extern.slf4j.Slf4j;
  3. importorg.springframework.context.ApplicationContext;
  4. importorg.springframework.context.support.ClassPathXmlApplicationContext;
  5. @Slf4j
  6. publicclassBeanLifeCycleTest{
  7. publicstaticvoidmain(String[]args){
  8. log.info("======开始初始化Spring容器========");
  9. ApplicationContextfactory=newClassPathXmlApplicationContext("application-beans.xml");
  10. log.info("======初始化Spring容器成功========");
  11. //获取Author实例
  12. Authorauthor=factory.getBean("author",Author.class);
  13. log.info(author.toString());
  14. log.info("======开始销毁Spring容器========");
  15. ((ClassPathXmlApplicationContext)factory).registerShutdownHook();
  16. }
  17. }

4.运行结果

运行结果如下:

  1. 15:49:12.477[main]INFOcom.tom.lifecycle.GPBeanPostProcessor-调用BeanPostProcessor实现类构造器!!
  2. 15:49:12.494[main]INFOcom.tom.lifecycle.Author-【构造器】调用Tom类的构造器实例化
  3. 15:49:12.527[main]INFOcom.tom.lifecycle.Author-【注入属性】address
  4. 15:49:12.528[main]INFOcom.tom.lifecycle.Author-【注入属性】age
  5. 15:49:12.528[main]INFOcom.tom.lifecycle.Author-【注入属性】name
  6. 15:49:12.528[main]INFOcom.tom.lifecycle.Author-【BeanNameAware接口】调用setBeanName方法
  7. 15:49:12.528[main]INFOcom.tom.lifecycle.Author-【BeanFactoryAware接口】调用setBeanFactory方法
  8. 15:49:12.528[main]INFOcom.tom.lifecycle.GPBeanPostProcessor-BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改
  9. 15:49:12.528[main]INFOcom.tom.lifecycle.Author-【InitializingBean接口】调用afterPropertiesSet方法
  10. 15:49:12.528[main]INFOcom.tom.lifecycle.Author-【init-method】调用<bean>的init-method属性指定的初始化方法
  11. 15:49:12.528[main]INFOcom.tom.lifecycle.GPBeanPostProcessor-BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改
  12. 15:49:12.531[main]INFOcom.tom.lifecycle.BeanLifeCycleTest-======初始化Spring容器成功========
  13. 15:49:12.531[main]INFOcom.tom.lifecycle.BeanLifeCycleTest-Author(name=Tom,address=湖南长沙,age=18,beanFactory=org.springframework.beans.factory.support.DefaultListableBeanFactory@26653222:definingbeans[beanPostProcessor,author];rootoffactoryhierarchy,beanName=author)
  14. 15:49:12.531[main]INFOcom.tom.lifecycle.BeanLifeCycleTest-======开始销毁Spring容器========
  15. 15:49:12.532[Thread-0]INFOcom.tom.lifecycle.Author-【DiposibleBean接口】调用destroy方法
  16. 15:49:12.533[Thread-0]INFOcom.tom.lifecycle.Author-【destroy-method】调用<bean>的destroy-method属性指定的初始化方法

我们看到,整个执行和我们一开始绘制的流程图一致。但是为什么我们要实现BeanFactoryPostProcessor接口呢?我们进入到BeanFactoryPostProcessor的源码如下:

  1. packageorg.springframework.beans.factory.config;
  2. importorg.springframework.beans.BeansException;
  3. publicinterfaceBeanFactoryPostProcessor{
  4. voidpostProcessBeanFactory(ConfigurableListableBeanFactoryvar1)throwsBeansException;
  5. }

BeanFactoryPostProcessor接口只有一个postProcessBeanFactory()方法,BeanFactoryPostProcessor:在BeanFactory标准初始化之后可以进行修改。将加载所有Bean定义,但是还没有实例化Bean。这个方法允许重新覆盖或者添加属性甚至快速的初始化bean。初次看到可能不知道postProcessBeanFactory()到底是干嘛的。要想透彻理解这个方法的作用,下面来进入到BeanFactoryPostProcessor的源码,理解一下postProcessBeanFactory()的参数,我们可以利用这些参数做一些操作。

通过参数来看,只有一个ConfigurableListableBeanFactory类,这个类的可以提供分析、修改Bean定义和预先实例化单例的功能。我们再进入到ConfigurableListableBeanFactory的源码中:

  1. publicinterfaceConfigurableListableBeanFactoryextendsListableBeanFactory,AutowireCapableBeanFactory,ConfigurableBeanFactory{
  2. //忽略被给定注入依赖类型,例如String
  3. voidignoreDependencyType(Class<?>var1);
  4. //略被给定注入依赖接口。这个通常被使用由ApplicationContext去注册依赖,可以以多种方式实现。例如BeanFactory通过BeanFactoryAware,ApplicationContext通过ApplicationContextAware。默认情况下,仅BeanFactoryAware接口是被忽略,需要忽略其他接口,调用此方法
  5. voidignoreDependencyInterface(Class<?>var1);
  6. //注册一个特定类型依赖伴随着相应的Autowired值。这个是准备被用于应该可以Autowire而不是在这个工厂被定义的Bean的工厂/上下文引用。例如将ApplicationContext类型的依赖项解析为Bean所在的ApplicationContext实例。注意~在普通的BeanFactory中没有注册这样的默认类型,甚至连BeanFactory接口本身都没有
  7. voidregisterResolvableDependency(Class<?>var1,Objectvar2);
  8. //确认这个被指定的Bean是否是一个Autowire候选,将被注入到其他声明匹配类型的依赖的Bean中
  9. booleanisAutowireCandidate(Stringvar1,DependencyDescriptorvar2)throwsNoSuchBeanDefinitionException;
  10. //根据指定的beanName返回被注册的Bean定义,允许访问其属性值和构造函数参数值(可以在BeanFactory后期处理期间被修改)。这个被返回的BeanDefinition对象不应该是副本而是原始在工厂被注册的。这意味着如果需要它可以被转换为更具体的实现类型。注意这个方法只能获得本地工厂BeanDefinition
  11. BeanDefinitiongetBeanDefinition(Stringvar1)throwsNoSuchBeanDefinitionException;
  12. //冻结全部Bean定义,给被注册的Bean定义发信号告诉它们今后不再被修改和进一步后续处理。它允许Factory去积极缓存Bean定义元数据
  13. voidfreezeConfiguration();
  14. //返回该工厂的BeanDefinnition是否被冻结
  15. booleanisConfigurationFrozen();
  16. //确保所有非懒加载的单例Bean被实例化,包括FactoryBean
  17. voidpreInstantiateSingletons()throwsBeansException;
  18. }

通过以上演示和分析,我们应该大概能够了解ConfigurableListableBeanFactory的作用,基本就都是对于Bean定义的操作。至此我们还没有看到BeanPostProcessor 和InstantiationAwareBeanPostProcessor的调用。下面我们把BeanPostProcessor 和InstantiationAwareBeanPostProcessor的实现补充上来,再看完整的执行流程

2.3 实现BeanPostProcessor

创建GPBeanPostProcessor类,并实现BeanPostProcessor 接口,具体代码如下:

  1. packagecom.tom.lifecycle;
  2. importlombok.extern.slf4j.Slf4j;
  3. importorg.springframework.beans.BeansException;
  4. importorg.springframework.beans.factory.config.BeanPostProcessor;
  5. @Slf4j
  6. publicclassGPBeanPostProcessorimplementsBeanPostProcessor{
  7. publicGPBeanPostProcessor(){
  8. log.info("调用BeanPostProcessor实现类构造器!!");
  9. }
  10. publicObjectpostProcessBeforeInitialization(Objecto,Strings)throwsBeansException{
  11. log.info("BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改");
  12. returno;
  13. }
  14. publicObjectpostProcessAfterInitialization(Objecto,Strings)throwsBeansException{
  15. log.info("BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改");
  16. returno;
  17. }
  18. }

ApplicationContext 可以在BeanDefinition中自动检测到实现了BeanPostProcessor的Bean,并且把这些Bean应用于随后的Bean创建。普通的BeanFactory允许对后处理器进行程序化注册,通过工厂应用于所有Bean创建。BeanPostProcessor接口中主要有两个方法:| 方法名 | 解释 | | -------- | -------- | | postProcessBeforeInitialization | 在Bean实例化回调(例如InitializingBean的afterPropertiesSet 或者一个定制的init-method)之前应用此BeanPostProcessor | | postProcessAfterInitialization | 在bean实例化回调(例如InitializingBean的afterPropertiesSet 或者一个定制的init-method)之后应用此BeanPostProcessor |

2.4 实现InstantiationAwareBeanPostProcessor

创建GPInstantiationAwareBeanPostProcessor类,并实现InstantiationAwareBeanPostProcessorAdapter接口,具体代码如下:

  1. packagecom.tom.lifecycle;
  2. importlombok.extern.slf4j.Slf4j;
  3. importorg.springframework.beans.BeansException;
  4. importorg.springframework.beans.PropertyValues;
  5. importorg.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
  6. importjava.beans.PropertyDescriptor;
  7. @Slf4j
  8. publicclassGPInstantiationAwareBeanPostProcessorextendsInstantiationAwareBeanPostProcessorAdapter{
  9. publicGPInstantiationAwareBeanPostProcessor(){
  10. super();
  11. log.info("调用InstantiationAwareBeanPostProcessorAdapter实现类构造器!!");
  12. }
  13. //接口方法、实例化Bean之前调用
  14. @Override
  15. publicObjectpostProcessBeforeInstantiation(ClassbeanClass,StringbeanName)throwsBeansException{
  16. log.info("InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法");
  17. returnnull;
  18. }
  19. //接口方法、实例化Bean之后调用
  20. @Override
  21. publicObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException{
  22. log.info("InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法");
  23. returnbean;
  24. }
  25. //接口方法、设置某个属性时调用
  26. @Override
  27. publicPropertyValuespostProcessPropertyValues(PropertyValuespvs,PropertyDescriptor[]pds,Objectbean,StringbeanName)throwsBeansException{
  28. log.info("InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法");
  29. returnpvs;
  30. }
  31. }

实现InstantiationAwareBeanPostProcessorAdapter的Bean之后,可以在实例化成功之后,做一些校验或者补充些内容或者把Bean包装代理注入。实现InstantiationAwareBeanPostProcessorAdapter的Bean之后,不会影响容器正常处理每一个实例化的Bean,其子类仅仅只是根据需要覆盖父类的方法。

注意,只有在实际需要 InstantiationAwareBeanPostProcessor 功能时才推荐此基类。如果我们所需要的只是简单的BeanPostProcessor功能,那么直接实现更简单的接口即可。

下面详细介绍一下InstantiationAwareBeanPostProcessorAdapter接口中的所有方法:

spring bean生命周期 面试(spring的生命周期面试题)

2.5 修改配置文件

完整的配置文件内容如下:

  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <beansxmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"
  4. xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"
  5. xsi:schemaLocation="
  6. http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
  8. <beanid="beanPostProcessor"class="com.tom.lifecycle.GPBeanPostProcessor"/>
  9. <beanid="beanFactoryPostProcessor"class="com.tom.lifecycle.GPBeanFactoryPostProcessor"/>
  10. <beanid="instantiationAwareBeanPostProcessor"class="com.tom.lifecycle.GPInstantiationAwareBeanPostProcessor"/>
  11. <beanid="author"class="com.tom.lifecycle.Author"
  12. init-method="beanInit"
  13. destroy-method="beanDestory"
  14. scope="singleton"
  15. p:name="Tom"p:address="湖南长沙"p:age="18"/>
  16. </beans>

2.6 运行结果

最后,我们再次运行BeanLifeCycleTest测试类,看到如下运行结果:

  1. 15:56:20.030[main]INFOcom.tom.lifecycle.GPBeanFactoryPostProcessor-调用BeanFactoryPostProcessor实现类构造器!!
  2. 15:56:20.045[main]INFOcom.tom.lifecycle.GPBeanFactoryPostProcessor-BeanFactoryPostProcessor调用postProcessBeanFactory方法
  3. 15:56:20.046[main]INFOcom.tom.lifecycle.GPBeanPostProcessor-调用BeanPostProcessor实现类构造器!!
  4. 15:56:20.047[main]INFOcom.tom.lifecycle.GPInstantiationAwareBeanPostProcessor-调用InstantiationAwareBeanPostProcessorAdapter实现类构造器!!
  5. 15:56:20.051[main]INFOcom.tom.lifecycle.GPInstantiationAwareBeanPostProcessor-InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法
  6. 15:56:20.052[main]INFOcom.tom.lifecycle.Author-【构造器】调用Tom类的构造器实例化
  7. 15:56:20.069[main]INFOcom.tom.lifecycle.GPInstantiationAwareBeanPostProcessor-InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法
  8. 15:56:20.092[main]INFOcom.tom.lifecycle.Author-【注入属性】address
  9. 15:56:20.092[main]INFOcom.tom.lifecycle.Author-【注入属性】age
  10. 15:56:20.092[main]INFOcom.tom.lifecycle.Author-【注入属性】name
  11. 15:56:20.092[main]INFOcom.tom.lifecycle.Author-【BeanNameAware接口】调用setBeanName方法
  12. 15:56:20.092[main]INFOcom.tom.lifecycle.Author-【BeanFactoryAware接口】调用setBeanFactory方法
  13. 15:56:20.093[main]INFOcom.tom.lifecycle.GPBeanPostProcessor-BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改
  14. 15:56:20.093[main]INFOcom.tom.lifecycle.Author-【InitializingBean接口】调用afterPropertiesSet方法
  15. 15:56:20.093[main]INFOcom.tom.lifecycle.Author-【init-method】调用<bean>的init-method属性指定的初始化方法
  16. 15:56:20.093[main]INFOcom.tom.lifecycle.GPBeanPostProcessor-BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改
  17. 15:56:20.093[main]INFOcom.tom.lifecycle.GPInstantiationAwareBeanPostProcessor-InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法
  18. 15:56:20.097[main]INFOcom.tom.lifecycle.BeanLifeCycleTest-======初始化Spring容器成功========
  19. 15:56:20.098[main]INFOcom.tom.lifecycle.BeanLifeCycleTest-Author(name=Tom,address=湖南长沙,age=16,beanFactory=org.springframework.beans.factory.support.DefaultListableBeanFactory@26653222:definingbeans[beanPostProcessor,beanFactoryPostProcessor,instantiationAwareBeanPostProcessor,author];rootoffactoryhierarchy,beanName=author)
  20. 15:56:20.098[main]INFOcom.tom.lifecycle.BeanLifeCycleTest-======开始销毁Spring容器========
  21. 15:56:20.099[Thread-0]INFOcom.tom.lifecycle.Author-【DiposibleBean接口】调用destroy方法
  22. 15:56:20.100[Thread-0]INFOcom.tom.lifecycle.Author-【destroy-method】调用<bean>的destroy-method属性指定的初始化方法

三、Spring Bean生命周期运行时序图

最后我们来看一下完整的执行时序图:

spring bean生命周期 面试(spring的生命周期面试题)

原文链接:https://mp.weixin.qq.com/s/xNgNBanu-HRm52j8oruasg

如果您对该产品感兴趣,请填写办理(客服微信:xiaoxiongyidong)

为您推荐:

发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。