Spring中Bean的生命周期概览
前言
最初,JavaBean的目的是为了将可以重复使用的软件代码打包标准。特别是用于帮助厂家开发在综合开发环境(IDE)下使用的java软件部件。这些包括如Grid控件,用户可以将该部件拖放到开发环境中。从此,JavaBean就可以扩展为一个java web 应用的标准部件,并且JavaBean部件框架已经扩展为企业版的 Bean(EJB)。
什么是Bean
首先,我们来看看Spring官方文档对于Bean的定义:
In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application
从上面可知,我们可以给Bean下一个定义:Bean就是由IOC实例化、组装、管理的一个对象。
Bean的生命周期
我们需要明确的是,在这里我们的Bean的生命周期主要指的是singleton bean,对prototype bean来说,当用户getBean获得prototype bean的实例后,IOC容器就不再对当前实例进行管理,而是把管理权交由用户,此后再getBean生成的是新的实例。对于request/session/application/websocket 这几种scope的bean我们在此不谈。
在不同的容器中,Bean的生命周期开始的时间不同。对于ApplicationContext来说,当容器启动的时候,bean就已经实例化了。而对于BeanFactory来说,直到调用getBean()方法的时候才进行实例化。
我们知道对于普通的java对象来说,它们的生命周期就是
- 实例化
- 不再使用的时候通过垃圾回收机制进行回收
但是对于Bean来说却不是这样。Bean的生命周期如下图所示
对于如上这些方法,我们可以分成如下几类
- Bean自身的方法:比如构造函数、getter/setter以及init-method和destory-method所指定的方法等
- Bean级生命周期方法:可以理解为Bean类直接实现接口的方法,比如BeanNameAware、BeanFactoryAware、ApplicationContextAware、InitializingBean、DisposableBean等方法,这些方法只对当前Bean生效
- 容器级的方法(BeanPostProcessor一系列接口):主要是后处理器方法,比如上图的InstantiationAwareBeanPostProcessor、BeanPostProcessor接口方法。这些接口的实现类是独立于bean的,并且会注册到Spring容器中。在Spring容器创建任何Bean的时候,这些后处理器都会发生作用。
- 工厂后处理器方法(BeanFactoryProcessor一系列接口):包括AspectJWeavingEnabler、CustomAutowireConfigurer、ConfigurationClassPostProcessor等。这些都是Spring框架中已经实现好的BeanFactoryPostProcessor,用来实现某些特定的功能。
Bean自身的方法和Bean级生命周期方法都只对当前Bean起作用,但是容器级生命周期方法和工厂后处理器方法是对所有的bean都起作用
对于这几类方法,1 2 4都很好理解,下面我们重点来说一下什么是BeanPostProcessor和BeanFactoryPostProcessor
以我个人理解来说,BeanPostProcessor和BeanFactoryPostProcessor就是Spring创建的扩展点,用户可以创建自己的实现类来修改Bean或者BeanFactory
注意对于ApplicatonContext来说,容器可以自动检测并加载BeanPostProcessor和BeanFactoryPostProcessor,但是BeanFactory不行,需要自己调用方法手动注册。BeanPostProcessor和BeanFactoryPostProcessor都可以有多个。ApplicationContext也可以根据org.springframework.core.PriorityOrdered和org.springframework.core.Ordered来进行自定义排序,但是BeanFactory不可以,默认顺序就是注册顺序。
这里我需要说明下面两个容易混淆的单词:
- Instantiation:实例化,指的是调用构造函数进行实例化
- Initialization:初始化,在Bean的声明周期中指的是init-method所指定的方法或者是InitializingBean.afterPropertiesSet()方法
下面我们对常用的这些接口进行说明:
常用接口说明
- BeanNameAware该接口只有一个方法setBeanName(String name),用来获取bean的id或者name
- BeanFactoryAware该接口只有一个方法setBeanFactory(BeanFactory beanFactory),用来获取当前环境中的BeanFactory
- ApplicationContextAware该接口只有一个方法setApplicationContext(ApplicationContext applicationContext),用来获取当前环境中的ApplicationContext 获取到IOC容器之后,可以对beans进行修改等操作
- InitializingBean该接口只有一个方法afterPropertiesSet(),在属性注入完成后调用
- DisposableBean该接口只有一个方法destroy(),在容器销毁的时候调用,在用户指定的destroy-method之前调用
- BeanPostProcessor该接口有两个方法:
- postProcessBeforeInitialization(Object bean, String beanName):在初始化之前调用此方法
- postProcessAfterInitialization(Object bean, String beanName):在初始化之后调用此方法
通过方法签名我们可以知道,我们可以通过beanName来筛选出我们需要进行个性化定制的bean
- InstantiationAwareBeanPostProcessor
该类是BeanPostProcessor的子接口,常用的有如下三个方法
- postProcessBeforeInstantiation(Class beanClass, String beanName):在bean实例化之前调用
- postProcessProperties(PropertyValues pvs, Object bean, String beanName):在bean实例化之后、设置属性前调用
- postProcessAfterInstantiation(Class beanClass, String beanName):在Bean实例化之后调用
测试Bean生命周期
下面我们来编写一个实例来验证我们上面所说的Bean生命周期
首先,我们新建一个User,这个Bean实现了我们的BeanNameAware、ApplicationContextAware、InitializingBean、DisposableBean接口
然后我们实现我们自己的BeanPostProcessor
实现自己的InstantiationAwareBeanPostProcessor
xml配置文件如下
<context:component-scan base-package="com.xiaohuan.springtest"/>
<bean id="user" class="com.xiaohuan.springtest.beanlifecycle.User" init-method="myInit" destroy-method="myDestroy">
<!-- 构造函数注入 -->
<constructor-arg index="0" type="int">
<value>1</value>
</constructor-arg>
<constructor-arg index="1" type="java.lang.String">
<value>xiaohuan</value>
</constructor-arg>
<!-- setter方法注入 -->
<property name="id" value="2"/>
<property name="name" value="dahuan"/>
</bean>
复制代码
编写我们自己的测试类
最后运行项目
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构