spring-bean的生命周期
Posted levontor
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring-bean的生命周期相关的知识,希望对你有一定的参考价值。
参考:
作者:浅然_
https://blog.csdn.net/w_linux/article/details/80086950
spring就是一个能够替你做很多事情的工厂,spring容器中的Bean就是该工厂的产品。要想使用Spring工厂生产和管理Bean,就需要在配置文件中指明需要哪些Bean,以及需要使用何种方式将这些Bean装配到一起。
在IoC容器启动之后,并不会马上就实例化相应的bean,此时容器仅仅拥有所有对象的BeanDefinition(BeanDefinition:是容器依赖某些工具加载的XML配置信息进行解析和分析,并将分析后的信息编组为相应的BeanDefinition)。只有当getBean()调用时才是有可能触发Bean实例化阶段的活动
通过图片了解一下bean的生命周期。
加载spring容器:BeanFactory
1.instantiate bean对象实例化
2.populate properties 封装属性
3.如果Bean实现BeanNameAware 执行 setBeanName
4.如果Bean实现BeanFactoryAware 执行setBeanFactory ,获取Spring容器
5.如果存在类实现 BeanPostProcessor(后处理Bean) ,执行postProcessBeforeInitialization
6.如果Bean实现InitializingBean 执行 afterPropertiesSet
7.调用<bean init-method="init"> 指定初始化方法 init
8.如果存在类实现 BeanPostProcessor(处理Bean) ,执行postProcessAfterInitialization
执行业务处理
9.如果Bean实现 DisposableBean 执行 destroy
10.调用<bean destroy-method="customerDestroy"> 指定销毁方法 customerDestroy
加载spring容器方式:应用上下文(类路径装载应用上下文与文件系统中装载应用上下文,即类路径与文件系统路径)
参考:https://www.cnblogs.com/kenshinobiy/p/4652008.html
1、实例化一个Bean--也就是我们常说的new;
2、按照Spring上下文对实例化的Bean进行配置--也就是IOC注入;
3、如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值
4、如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其它Bean,只需在Spring配置文件中配置一个普通的Bean就可以);
5、如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);
6、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;
7、如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。
8、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法、;
注:以上工作完成以后就可以应用这个Bean了,那这个Bean是一个Singleton的,所以一般情况下我们调用同一个id的Bean会是在内容地址相同的实例,当然在Spring配置文件中也可以配置非Singleton,这里我们不做赘述。
9、当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destroy()方法;
10、最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
以上10步骤可以作为面试或者笔试的模板,另外我们这里描述的是应用Spring上下文Bean的生命周期,如果应用Spring的工厂也就是BeanFactory的话去掉第5步就Ok了。
说明
1. Bean生命周期要经历很多阶段,但这些阶段大部分都是可选的。例如,某个Bean如果实现了BeanFactoryAware接口的setBeanFactory方法,那么该Bean的生命就会经历这个阶段,如果不实现则没有。
2. BeanFactoryPostProcessor接口与BeanPostProcessor接口的作用范围是整个上下文环境中,使用方法是单独新增一个类来实现这些接口,那么在处理其他Bean的某些时刻就会回调响应的接口中的方法。
3、BeanNameAware、BeanFactoryAware、ApplicationContextAware的作用范围的Bean范围,即仅仅对实现了该接口的指定Bean有效,所有其使用方法是在要使用该功能的Bean自己来实现该接口。
4、InitializingBean的afterPropertiesSet()方法 与 自定义的inti-method指定的方法 两个初始化方法作用是一样的,我们完全可以使用其中的一种即可,一般情况我们使用自定义的inti-method指定的方法的方式,尽量少的去来Bean中实现某些接口,保持其独立性,低耦合性,尽量不要与Spring代码耦合在一起。DisposableBean的destory()方法 和自定义的destory-method指定的方法也是如此。
下面就解释一下这些接口都有什么作用:
参考:https://www.jianshu.com/p/d7e45100f934
https://www.cnblogs.com/xiaozhuanfeng/p/10790695.html(里面有代码)
BeanNameAware接口:
让bean对name或id有知觉。即为了让自身Bean能够感知到,获取到自身在Spring容器中的id或name属性。
让Bean获取自己在BeanFactory配置中的名字(根据情况是id或者name)。
Spring自动调用。并且会在Spring自身完成Bean配置之后,且在调用任何Bean生命周期回调(初始化或者销毁)方法之前就调用这个方法。换言之,在程序中使用BeanFactory.getBean(String beanName)之前,Bean的名字就已经设定好了。
BeanFactoryAware接口:
参考:https://blog.csdn.net/wang704987562/article/details/80716267
Spring提供了一个BeanPostProcessor接口,这个接口的作用在于对于新构造的实例可以做一些自定义的修改。比如如何构造、属性值的修改、构造器的选择。
如果想改变Spring容器中bean的一些属性或者行为,可以通过自定义类实现BeanPostProcessor接口实现。
总结:
1.postProcessBeforeInitialization方法的作用在于目标对象实例化之后,初始化之前调用,默认返回原始对象,也可以返回一个包装实例;
如果返回null,接下来的BeanPostProcessors都不会执行
2.postProcessAfterInitialization方法的作用在于目标对象实例化之后,初始化之后调用,默认返回原始对象,也可以返回一个包装实例;
如果返回null,接下来的BeanPostProcessors都不会执行
3.初始化(Initialization):表示生成对象,未设置属性;初始化之前表示bean的初始化回调之前,如InitializingBean接口的afterPropertiesSet方法或者自定义的init-method方法。
https://www.cnblogs.com/V1haoge/p/6106456.html
最后的总结:图片很清楚,bean--实例化-->初始化-->使用-->销毁。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------、
接下来如果各位大佬想继续深挖,参考一下这篇文章:
---------------------
参考:https://blog.csdn.net/u010634066/article/details/80321854
https://cloud.tencent.com/developer/article/1409273
https://blog.csdn.net/u010634066/article/details/80289441
Spring对对象的可扩展性主要就是依靠InstantiationAwareBeanPostProcessor和BeanPostProcessor来实现的。
- InstantiationAwareBeanPostProcessor 主要是作用于实例化阶段。
- BeanPostProcessor 主要作用与 初始化阶段。
InstantiationAwareBeanPostProcessor接口继承BeanPostProcessor接口,它内部提供了3个方法,再加上BeanPostProcessor接口内部的2个方法,所以实现这个接口需要实现5个方法。
InstantiationAwareBeanPostProcessor接口的主要作用在于目标对象的实例化过程中需要处理的事情,包括实例化对象的前后过程以及实例的属性设置。
InstantiationAwareBeanPostProcessor接口的源代码:
1 package org.springframework.beans.factory.config; 2 public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor { 3 4 Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException; 5 6 boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException; 7 8 PropertyValues postProcessPropertyValues( 9 PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException; 10 11 }
从源码中我们可以获知的信息是该接口除了具有父接口中的两个方法以外还自己额外定义了三个方法。所以该接口一共定义了5个方法,这5个方法的作用分别是:
注意实例化与初始化两个单词不同
Instantiation |
表示实例化,对象还未生成 |
Initialization |
表示初始化,对象已经生成 |
方法 |
描述 |
---|---|
postProcessBeforeInitialization |
BeanPostProcessor接口中的方法,在Bean的自定义初始化方法之前执行 |
postProcessAfterInitialization |
BeanPostProcessor接口中的方法 在Bean的自定义初始化方法执行完成之后执行 |
postProcessBeforeInstantiation |
自身方法,是最先执行的方法,它在目标对象实例化之前调用,该方法的返回值类型是Object,我们可以返回任何类型的值。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(比如代理对象)。如果该方法的返回值代替原本该生成的目标对象,后续只有postProcessAfterInitialization方法会调用,其它方法不再调用;否则按照正常的流程走 |
postProcessAfterInstantiation |
在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是null。因为它的返回值是决定要不要调用postProcessPropertyValues方法的其中一个因素(因为还有一个因素是mbd.getDependencyCheck());如果该方法返回false,并且不需要check,那么postProcessPropertyValues就会被忽略不执行;如果返回true,postProcessPropertyValues就会被执行 |
postProcessPropertyValues |
对属性值进行修改,如果postProcessAfterInstantiation方法返回false,该方法可能不会被调用。可以在该方法内对属性值进行修改 |
调用方法顺序
1. postProcessBeforeInstantiation方法
(代码示例https://cloud.tencent.com/developer/article/1409273)就不粘贴了 ,但是大家一定要先阅读代码,再看总结。
a. 返回的结果如果为null,后面的方法都正常执行了后面均正常执行。
b.但是如果该方法返回了实例对象
postProcessBeforeInstantiation方法返回实例对象后跳过了对象的初始化操作,直接执行了postProcessAfterInitialization(该方法在自定义初始化方法执行完成之后执行),跳过了postProcessAfterInstantiation,postProcessPropertyValues以及自定义的初始化方法
2. postProcessAfterInstantiation方法
postProcessAfterInstantiation返回值要注意,因为它的返回值是决定要不要调用postProcessPropertyValues方法的其中一个因素
(因为还有一个因素是mbd.getDependencyCheck())---->如果该方法返回false,并且不需要check,那么postProcessPropertyValues就会被忽略不执行;如果返true,postProcessPropertyValues就会被执行
3.postProcessPropertyValues方法
对属性值进行修改
总结:
1.InstantiationAwareBeanPostProcessor接口继承BeanPostProcessor接口,它内部提供了3个方法,再加上BeanPostProcessor接口内部的2个方法,所以实现这个接口需要实现5个方法。InstantiationAwareBeanPostProcessor接口的主要作用在于目标对象的实例化过程中需要处理的事情,包括实例化对象的前后过程以及实例的属性设置
2.postProcessBeforeInstantiation方法是最先执行的方法,它在目标对象实例化之前调用,该方法的返回值类型是Object,我们可以返回任何类型的值。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(比如代理对象)。如果该方法的返回值代替原本该生成的目标对象,后续只有postProcessAfterInitialization方法会调用,其它方法不再调用;否则按照正常的流程走
3. postProcessAfterInstantiation方法在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是null。因为它的返回值是决定要不要调用postProcessPropertyValues方法的其中一个因素(因为还有一个因素是mbd.getDependencyCheck());如果该方法返回false,并且不需要check,那么postProcessPropertyValues就会被忽略不执行;如果返回true, postProcessPropertyValues就会被执行
4.postProcessPropertyValues方法对属性值进行修改(这个时候属性值还未被设置,但是我们可以修改原本该设置进去的属性值)。如果postProcessAfterInstantiation方法返回false,该方法可能不会被调用。可以在该方法内对属性值进行修改
5.父接口BeanPostProcessor的2个方法postProcessBeforeInitialization和postProcessAfterInitialization都是在目标对象被实例化之后,并且属性也被设置之后调用的
以上是关于spring-bean的生命周期的主要内容,如果未能解决你的问题,请参考以下文章