首页 > 编程知识 正文

springboot生命周期面试,spring的两大特性 面试

时间:2023-05-06 00:33:48 阅读:182256 作者:4494

Spring Bean的生命周期是Spring面试的热点问题。 这个问题是考察对Spring的微观理解和对Spring的宏观认识,要回答好并不容易! 本文希望从源代码的角度入手,帮助面试者全面处理Spring Bean的生命周期。

只有四个! 是的,Spring Bean的生命周期只有这四个阶段。 把这四个阶段和每个阶段对应的扩展点混合在一起是没有问题的,但这非常乱,很难记忆。 要彻底弄清Spring的生命周期,首先要牢牢记住这四个阶段。 实例化和属性赋值支持构建方法和setter方法的注入,初始化和销毁是用户可以自定义扩展的两个阶段。 稍后将介绍在这四个步骤之间插入的各种扩展点。

实例化实例化属性赋值Populate初始化Initialization销毁实例化-属性赋值-初始化-销毁

所有主要逻辑都位于doCreate ()方法中。 逻辑清晰的地方是按顺序调用以下三种方法。 这三种方法与三个生命周期阶段一一对应,非常重要,也涉及后续的扩展接口分析。

createbeaninstance(-实例化populateBean ) -属性赋值initializeBean ) -初始化源代码如下所示,证明存在三个生命周期:实例化、属性赋值和初始化对于本文的Spring源代码,忽略无关的部分使其更容易理解。

在容器关闭时调用销毁。 有关详细信息,请参阅configurableapplicationcontext # close ()。

一般扩展点

关于Spring生命周期的常见扩展非常多,所以问题不是不知道,而是记不住或记不住。 其实记不住的根本原因还不充分,这里用源代码的分类方法帮助大家记忆。

第一个是影响多个Bean的接口

实现这些接口的Bean将进入多个Bean的生命周期。 因此,这些接口非常强大,Spring的内部扩展也经常使用这些接口。 例如,自动注入和AOP的实现与他们有关。

beanpostprocessorinstantiationawarebeanpostprocessor这两个兄弟可能是Spring扩展中最重要的两个接口! instantiationawarebeanpostprocessor作用于实例化阶段的前后,beanpostprocessor作用于初始化阶段的前后。 正好对应于第一、第三个生命周期阶段。 通过图可以更好地理解:

instantiationawarebeanpostprocessor实际上继承了beanpostprocessor接口,严格来说不是两个兄弟,而是两个父子。 但是,从生命周期的观点出发,将焦点放在对其特有的实例化阶段的影响上,图中省略了从BeanPostProcessor继承的方法。

instantiationawarebeanpostprocessorextendsbeanpostprocessorinstantiationawarebeanpostprocessor源代码分析:

postProcessBeforeInstantiation调用点,忽略无关代码:

正如您所看到的,postProcessBeforeInstantiation在doCreateBean之前,即在实例化bean之前调用。 英语源注释解释说,此方法的返回值将原始bean替换为代理也是实现Aop等功能的关键。

postProcessAfterInstantiation调用点,忽略无关代码:

此方法位于属性赋值方法中,但在实际执行赋值操作之前显示。 其返回值为boolean,如果返回false,则可以阻止属性赋值阶段(continuewithpropertypopulation=false; 请参阅。

BeanPostProcessor执行阶段的源代码已包括在以下Aware接口的调用计时分析中: 因为Aware的部分功能是由他实现的。首先,你只需要记住BeanPostProcessor在初始化前后调用。

第二个类别:只调用一次的接口

这种接口的特点是功能丰富,常用于用户定制扩展。

在第二类中,可以分为以下两类:

Aware类型的接口生命周期接口不知道Aware

Aware类型接口的作用是获得Spring容器中的一些资源。 基本上,我可以知道名字。 Aware的名字是能得到什么样的资源。 例如,BeanNameAware可以得到BeanName。 呼叫的时机需要注意。 所有Aware方法都在初始化阶段之前调用。

Aware接口很多,这里也通过分类帮助大家记忆。

Aware界面具体可以分为两组。 有关为什么这样划分的详细信息,请参阅下面的源代码分析。 以下的排列顺序也同样是Aware界面的执行顺序,可以看出其有名的含义

的接口不再解释。

Aware Group1

BeanNameAwareBeanClassLoaderAwareBeanFactoryAware

Aware Group2

EnvironmentAwareEmbeddedValueResolverAware 这个知道的人可能不多,实现该接口能够获取Spring EL解析器,用户的自定义注解需要支持spel表达式的时候可以使用,非常方便。ApplicationContextAware(ResourceLoaderAwareApplicationEventPublisherAwareMessageSourceAware) 这几个接口可能让人有点懵,实际上这几个接口可以一起记,其返回值实质上都是当前的ApplicationContext对象,因为ApplicationContext是一个复合接口,如下:

 

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {}

这里涉及到另一道面试题,ApplicationContext和BeanFactory的区别,可以从ApplicationContext继承的这几个接口入手,除去BeanFactory相关的两个接口就是ApplicationContext独有的功能,这里不详细说明。

Aware调用时机源码分析

详情如下,忽略了部分无关代码。代码位置就是我们上文提到的initializeBean方法详情,这也说明了Aware都是在初始化阶段之前调用的!

 

可以看到并不是所有的Aware接口都使用同样的方式调用。Bean××Aware都是在代码中直接调用的,而ApplicationContext相关的Aware都是通过BeanPostProcessor#postProcessBeforeInitialization()实现的。

感兴趣的可以自己看一下ApplicationContextAwareProcessor这个类的源码,就是判断当前创建的Bean是否实现了相关的Aware方法,如果实现了会调用回调方法将资源传递给Bean。

至于Spring为什么这么实现,应该没什么特殊的考量。也许和Spring的版本升级有关。基于对修改关闭,对扩展开放的原则,Spring对一些新的Aware采用了扩展的方式添加。

BeanPostProcessor的调用时机也能在这里体现,包围住invokeInitMethods方法,也就说明了在初始化阶段的前后执行。

关于Aware接口的执行顺序,其实只需要记住第一组在第二组执行之前就行了。每组中各个Aware方法的调用顺序其实没有必要记,有需要的时候点进源码一看便知。

简单的两个生命周期接口

至于剩下的两个生命周期接口就很简单了,实例化和属性赋值都是Spring帮助我们做的,能够自己实现的有初始化和销毁两个生命周期阶段。

InitializingBean 对应生命周期的初始化阶段,在上面源码的invokeInitMethods(beanName, wrappedBean, mbd);方法中调用。

有一点需要注意,因为Aware方法都是执行在初始化方法之前,所以可以在初始化方法中放心大胆的使用Aware接口获取的资源,这也是我们自定义扩展Spring的常用方式。

除了实现InitializingBean接口之外还能通过注解或者xml配置的方式指定初始化方法,至于这几种定义方式的调用顺序其实没有必要记。因为这几个方法对应的都是同一个生命周期,只是实现方式不同,我们一般只采用其中一种方式。

DisposableBean 类似于InitializingBean,对应生命周期的销毁阶段,以ConfigurableApplicationContext#close()方法作为入口,实现是通过循环取所有实现了DisposableBean接口的Bean然后调用其destroy()方法 。感兴趣的可以自行跟一下源码。

扩展阅读: BeanPostProcessor 注册时机与执行顺序

注册时机

我们知道BeanPostProcessor也会注册为Bean,那么Spring是如何保证BeanPostProcessor在我们的业务Bean之前初始化完成呢?

请看我们熟悉的refresh()方法的源码,省略部分无关代码:

 

可以看出,Spring是先执行registerBeanPostProcessors()进行BeanPostProcessors的注册,然后再执行finishBeanFactoryInitialization初始化我们的单例非懒加载的Bean。

执行顺序

BeanPostProcessor有很多个,而且每个BeanPostProcessor都影响多个Bean,其执行顺序至关重要,必须能够控制其执行顺序才行。关于执行顺序这里需要引入两个排序相关的接口:PriorityOrdered、Ordered

PriorityOrdered是一等公民,首先被执行,PriorityOrdered公民之间通过接口返回值排序,Ordered是二等公民,然后执行,Ordered公民之间通过接口返回值排序

都没有实现是三等公民,最后执行。

在以下源码中,可以很清晰的看到Spring注册各种类型BeanPostProcessor的逻辑,根据实现不同排序接口进行分组。优先级高的先加入,优先级低的后加入。

 

根据排序接口返回值排序,默认升序排序,返回值越低优先级越高。

/** * Useful constant for the highest precedence value. * @see java.lang.Integer#MIN_VALUE */ int HIGHEST_PRECEDENCE = Integer.MIN_VALUE; /** * Useful constant for the lowest precedence value. * @see java.lang.Integer#MAX_VALUE */ int LOWEST_PRECEDENCE = Integer.MAX_VALUE;

PriorityOrdered、Ordered接口作为Spring整个框架通用的排序接口,在Spring中应用广泛,也是非常重要的接口。

总结

Spring Bean的生命周期分为四个阶段和多个扩展点。扩展点又可以分为影响多个Bean和影响单个Bean。整理如下:

四个阶段

实例化 Instantiation属性赋值 Populate初始化 Initialization销毁 Destruction

多个扩展点

影响多个Bean

BeanPostProcessorInstantiationAwareBeanPostProcessor

影响单个Bean

Aware

Aware Group1BeanNameAwareBeanClassLoaderAwareBeanFactoryAwareAware Group2EnvironmentAwareEmbeddedValueResolverAwareApplicationContextAware(ResourceLoaderAwareApplicationEventPublisherAwareMessageSourceAware)

生命周期

InitializingBeanDisposableBean

转载于:https://my.oschina.net/u/3159571/blog/3064640

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。