深度解析Spring Bean生命周期以及LomBok插件
在Spring框架中,Bean的生命周期是核心知識(shí)點(diǎn)之一,也是面試中的高頻考點(diǎn)。相比于傳統(tǒng)Java應(yīng)用中Bean簡(jiǎn)單的“實(shí)例化-使用-垃圾回收”流程,Spring IOC容器對(duì)Bean的生命周期提供了完整的管理能力,支持在特定階段執(zhí)行定制化任務(wù)。本文將從核心差異入手,層層拆解Spring Bean的生命周期階段,結(jié)合具體代碼案例詳解生命周期回調(diào)方法的實(shí)現(xiàn)方式,并補(bǔ)充Bean后置處理器的關(guān)鍵知識(shí)點(diǎn),幫助大家徹底掌握這一核心內(nèi)容。
一、傳統(tǒng)Java vs Spring:Bean生命周期核心差異
在傳統(tǒng)Java應(yīng)用中,Bean的生命周期邏輯非常簡(jiǎn)單,完全由JVM主導(dǎo):
- 實(shí)例化:通過(guò)
new關(guān)鍵字調(diào)用構(gòu)造器創(chuàng)建Bean實(shí)例; - 使用:實(shí)例創(chuàng)建完成后直接調(diào)用方法即可使用;
- 銷毀:當(dāng)Bean長(zhǎng)期不被使用,失去引用后,JVM自動(dòng)執(zhí)行垃圾回收。
而Spring中的Bean生命周期則由IOC容器全程管理,流程更復(fù)雜,但靈活性更高——Spring允許我們?cè)贐ean生命周期的關(guān)鍵節(jié)點(diǎn)插入自定義邏輯,實(shí)現(xiàn)對(duì)Bean的精細(xì)化管控。這種管控能力也是Spring框架核心優(yōu)勢(shì)之一。
二、Spring Bean生命周期完整階段拆解
Spring Bean的生命周期從IOC容器初始化開(kāi)始,到IOC容器關(guān)閉結(jié)束,整個(gè)流程可拆解為8個(gè)核心階段,各階段按順序依次執(zhí)行:
- Bean對(duì)象創(chuàng)建:IOC容器初始化時(shí),通過(guò)Java反射機(jī)制調(diào)用Bean的無(wú)參構(gòu)造器,生成Bean的實(shí)例對(duì)象;
- Bean對(duì)象屬性注入:同樣通過(guò)反射機(jī)制,調(diào)用Bean的setter方法,將配置文件或注解中定義的屬性值注入到Bean實(shí)例中;
- Bean初始化前操作:由Bean后置處理器(BeanPostProcessor)的
postProcessBeforeInitialization方法負(fù)責(zé)執(zhí)行,屬于全局定制化操作; - Bean對(duì)象初始化:需在Bean配置時(shí)指定初始化方法(如接口實(shí)現(xiàn)、XML配置、注解方式),容器會(huì)調(diào)用該方法執(zhí)行初始化邏輯;
- Bean初始化后操作:由Bean后置處理器的
postProcessAfterInitialization方法負(fù)責(zé)執(zhí)行,同樣是全局生效的定制化操作; - Bean對(duì)象就緒可用:經(jīng)過(guò)以上階段后,Bean實(shí)例已完全初始化完成,可通過(guò)IOC容器的
getBean()方法獲取并使用; - Bean對(duì)象銷毀:需在Bean配置時(shí)指定銷毀方法,當(dāng)IOC容器關(guān)閉時(shí),容器會(huì)調(diào)用該方法執(zhí)行銷毀邏輯(如資源釋放);
- IOC容器關(guān)閉:容器完成所有Bean的銷毀后,自身關(guān)閉,生命周期結(jié)束。

提示:核心記憶點(diǎn)——“創(chuàng)建-注入-初始化前后-就緒-銷毀-容器關(guān)閉”,其中初始化前后的操作由后置處理器主導(dǎo),初始化和銷毀需自定義方法并配置。
三、Bean生命周期回調(diào)方法:3種實(shí)現(xiàn)方式與優(yōu)先級(jí)
Spring允許我們通過(guò)“生命周期回調(diào)方法”在Bean的初始化(第4階段)和銷毀(第7階段)時(shí)刻執(zhí)行自定義邏輯(如資源加載、連接關(guān)閉等)。共有3種實(shí)現(xiàn)方式,且存在明確的優(yōu)先級(jí)順序。
核心優(yōu)先級(jí)規(guī)則:注解 > 接口實(shí)現(xiàn) > XML配置
方式一:接口實(shí)現(xiàn)(InitializingBean + DisposableBean)
通過(guò)讓Bean類實(shí)現(xiàn)Spring提供的InitializingBean(初始化回調(diào))和DisposableBean(銷毀回調(diào))接口,重寫(xiě)接口中的方法即可實(shí)現(xiàn)定制邏輯。
1. 代碼實(shí)現(xiàn)
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class Dog implements InitializingBean, DisposableBean {
private String name;
private String owner;
private int age;
// 1. 無(wú)參構(gòu)造器:階段1(Bean對(duì)象創(chuàng)建)執(zhí)行
public Dog() {
System.out.println("Dog對(duì)象被創(chuàng)建...");
}
// Setter方法:階段2(屬性注入)執(zhí)行
public void setName(String name) {
System.out.println("調(diào)用setName方法....");
this.name = name;
}
public void setOwner(String owner) {
System.out.println("調(diào)用setOwner方法....");
this.owner = owner;
}
public void setAge(int age) {
System.out.println("調(diào)用setAge方法....");
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", owner='" + owner + '\'' +
", age=" + age +
'}';
}
// 2. 初始化回調(diào):實(shí)現(xiàn)InitializingBean接口,階段4執(zhí)行
// 該方法在屬性注入完成后調(diào)用
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("調(diào)用接口:InitializingBean,方法:afterPropertiesSet,無(wú)參數(shù)");
}
// 3. 銷毀回調(diào):實(shí)現(xiàn)DisposableBean接口,階段7執(zhí)行
// 該方法在容器關(guān)閉時(shí)調(diào)用
@Override
public void destroy() throws Exception {
System.out.println("調(diào)用接口:DisposableBean,方法:destroy,無(wú)參數(shù)");
}
}2. 注意事項(xiàng)
這種方式的缺點(diǎn)是耦合性高——Bean類直接依賴Spring框架的接口,導(dǎo)致代碼與Spring框架緊耦合,不利于后續(xù)的擴(kuò)展和遷移。因此,在實(shí)際開(kāi)發(fā)中,除非有特殊需求,否則不建議優(yōu)先使用。
方式二:XML配置(init-method + destroy-method)
通過(guò)Spring的XML配置文件,在<bean>標(biāo)簽中通過(guò)init-method屬性指定初始化方法名,通過(guò)destroy-method屬性指定銷毀方法名,無(wú)需Bean類實(shí)現(xiàn)任何接口,降低了耦合性。
1. 代碼實(shí)現(xiàn)
首先,在Dog類中定義自定義的初始化和銷毀方法(方法名可任意,無(wú)參數(shù)):
public class Dog {
private String name;
private String owner;
private int age;
public Dog() {
System.out.println("Dog對(duì)象被創(chuàng)建...");
}
// Setter方法省略...
// 自定義初始化方法:對(duì)應(yīng)init-method
public void initDog() {
System.out.println("XML配置:執(zhí)行自定義初始化方法 initDog");
}
// 自定義銷毀方法:對(duì)應(yīng)destroy-method
public void destroyDog() {
System.out.println("XML配置:執(zhí)行自定義銷毀方法 destroyDog");
}
// toString方法省略...
}然后,在XML配置文件(applicationContext.xml)中配置屬性:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置Dog Bean,指定初始化和銷毀方法 -->
<bean id="dog"
class="com.qcby.Dog"
p:name="admin"
p:owner="aaa"
p:age="18"
init-method="initDog"
destroy-method="destroyDog"/>
</beans>2. 核心優(yōu)勢(shì)
完全解耦:Bean類是純Java類,不依賴任何Spring接口或注解,通用性更強(qiáng),便于維護(hù)和遷移。適合基于XML配置的傳統(tǒng)Spring項(xiàng)目。
方式三:注解實(shí)現(xiàn)(@PostConstruct + @PreDestroy)
通過(guò)JDK提供的@PostConstruct(初始化回調(diào))和@PreDestroy(銷毀回調(diào))注解,直接標(biāo)注在Bean類的方法上,實(shí)現(xiàn)定制邏輯。這是目前開(kāi)發(fā)中最常用的方式,簡(jiǎn)潔高效且耦合性低。
1. 代碼實(shí)現(xiàn)
首先,需要引入lombok依賴(若未引入,也可直接使用注解,不影響功能):
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>然后,在Dog類中使用注解標(biāo)注方法:
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class Dog {
private String name;
private String owner;
private int age;
public Dog() {
System.out.println("Dog對(duì)象被創(chuàng)建...");
}
// Setter方法省略...
// 初始化回調(diào):@PostConstruct,階段4執(zhí)行
@PostConstruct
public void initByAnnotation() {
System.out.println("注解方式:執(zhí)行@PostConstruct標(biāo)注的初始化方法");
}
// 銷毀回調(diào):@PreDestroy,階段7執(zhí)行
@PreDestroy
public void destroyByAnnotation() {
System.out.println("注解方式:執(zhí)行@PreDestroy標(biāo)注的銷毀方法");
}
// toString方法省略...
}最后,在XML或注解配置中掃描該Bean(確保IOC容器能識(shí)別):
<!-- XML配置掃描包 --> <context:component-scan base-package="com.xxx"/>
2. 核心優(yōu)勢(shì)
1. 簡(jiǎn)潔高效:無(wú)需實(shí)現(xiàn)接口,無(wú)需XML配置,直接通過(guò)注解標(biāo)注即可;2. 耦合性低:注解是JDK原生提供(非Spring專屬),Bean類通用性強(qiáng);3. 優(yōu)先級(jí)最高:當(dāng)多種方式同時(shí)存在時(shí),注解標(biāo)注的方法會(huì)優(yōu)先執(zhí)行。
四、關(guān)鍵擴(kuò)展:Bean后置處理器(BeanPostProcessor)
Bean后置處理器是Spring提供的一種全局?jǐn)U展機(jī)制,它不針對(duì)某個(gè)特定的Bean,而是對(duì)IOC容器中所有的Bean生效,主要作用于Bean初始化的前后兩個(gè)階段(對(duì)應(yīng)生命周期的第3和第5階段)。
1. 核心作用
- 初始化前(postProcessBeforeInitialization):對(duì)初始化前的Bean實(shí)例進(jìn)行增強(qiáng)或修改;
- 初始化后(postProcessAfterInitialization):對(duì)初始化后的Bean實(shí)例進(jìn)行增強(qiáng)或修改(如AOP的動(dòng)態(tài)代理就是基于此實(shí)現(xiàn))。
2. 實(shí)現(xiàn)步驟
步驟1:創(chuàng)建后置處理器類
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
// 自定義Bean后置處理器,實(shí)現(xiàn)BeanPostProcessor接口
public class MyBeanProcessor implements BeanPostProcessor {
// 初始化前執(zhí)行
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("☆☆☆ 后置處理器-初始化前:" + beanName + " = " + bean);
return bean; // 必須返回bean實(shí)例,否則容器中無(wú)法獲取到該Bean
}
// 初始化后執(zhí)行
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("★★★ 后置處理器-初始化后:" + beanName + " = " + bean);
return bean;
}
}步驟2:將后置處理器注入IOC容器
后置處理器必須被IOC容器管理,才能生效。通過(guò)XML配置注入:
<!-- 注入Bean后置處理器 --> <bean id="myBeanProcessor" class="com.gs.process.MyBeanProcessor"/>
3. 執(zhí)行效果說(shuō)明
當(dāng)IOC容器初始化時(shí),會(huì)對(duì)所有Bean執(zhí)行以下流程:
Bean創(chuàng)建 → 屬性注入 → 后置處理器初始化前方法 → Bean初始化方法 → 后置處理器初始化后方法 → Bean就緒可用
控制臺(tái)會(huì)輸出類似如下內(nèi)容:

五、實(shí)戰(zhàn)測(cè)試:驗(yàn)證Bean生命周期流程
為了更直觀地理解整個(gè)生命周期流程,我們通過(guò)一個(gè)完整的測(cè)試案例來(lái)驗(yàn)證。
1. 測(cè)試類編寫(xiě)
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.xxx.Dog;
public class LifeCycleTest {
@Test
public void testLifeCycle() {
System.out.println("-------容器初始化階段---------");
// 初始化IOC容器(此時(shí)會(huì)觸發(fā)Bean的創(chuàng)建、屬性注入、初始化等流程)
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("-------對(duì)象使用階段---------");
// 獲取Bean實(shí)例并使用
Dog dog = ac.getBean("dog", Dog.class);
System.out.println(dog);
System.out.println("-------容器關(guān)閉階段---------");
// 手動(dòng)關(guān)閉容器(觸發(fā)Bean的銷毀流程)
ac.close(); // 注意:ApplicationContext接口無(wú)close方法,需使用其子類ClassPathXmlApplicationContext
}
}2. 測(cè)試結(jié)果與分析
控制臺(tái)輸出如下(結(jié)合注解方式和后置處理器):

輸出結(jié)果完全匹配我們之前拆解的生命周期階段,驗(yàn)證了流程的正確性。
六、核心知識(shí)點(diǎn)總結(jié)(面試必背)
- Spring Bean生命周期8階段:創(chuàng)建 → 注入 → 初始化前 → 初始化 → 初始化后 → 就緒 → 銷毀 → 容器關(guān)閉;
- 生命周期回調(diào)3種實(shí)現(xiàn)方式及優(yōu)先級(jí):注解(@PostConstruct/@PreDestroy)> 接口(InitializingBean/DisposableBean)> XML(init-method/destroy-method);
- Bean后置處理器作用:全局?jǐn)r截所有Bean的初始化前后階段,實(shí)現(xiàn)增強(qiáng)邏輯,是AOP的基礎(chǔ);
- 開(kāi)發(fā)建議:優(yōu)先使用注解方式實(shí)現(xiàn)回調(diào),低耦合、高效率;避免使用接口方式,減少與Spring框架的耦合。
七、LomBok
通過(guò)本文的講解,相信大家已經(jīng)對(duì)Spring Bean的生命周期有了全面且深入的理解。建議結(jié)合文中的代碼案例實(shí)際運(yùn)行測(cè)試,通過(guò)輸出結(jié)果加深對(duì)各階段的記憶,面試時(shí)才能做到游刃有余!
到此這篇關(guān)于深度解析Spring Bean生命周期以及LomBok插件的文章就介紹到這了,更多相關(guān)Spring Bean生命周期內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Intellij IDEA中如何查看maven項(xiàng)目中所有jar包的依賴關(guān)系圖
這篇文章主要介紹了Intellij IDEA中如何查看maven項(xiàng)目中所有jar包的依賴關(guān)系圖,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05
Java LinkedHashSet集合的底層原理和TreeSet集合
LinkedHashSet保證元素有序且唯一,底層通過(guò)雙鏈表實(shí)現(xiàn),TreeSet元素不重復(fù)且可排序,底層使用紅黑樹(shù)實(shí)現(xiàn)排序,自定義類型排序可通過(guò)實(shí)現(xiàn)Comparable接口或提供Comparator來(lái)定義排序規(guī)則,適用于需要大量元素快速檢索的場(chǎng)景2024-10-10
SpringBoot+kaptcha實(shí)現(xiàn)驗(yàn)證碼花式玩法詳解
這篇文章主要想和大家聊聊kaptcha的用法,畢竟這個(gè)已經(jīng)有16年歷史的玩意還在有人用,說(shuō)明它的功能還是相當(dāng)強(qiáng)大的,感興趣的小伙伴可以了解一下2022-05-05
用Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的布隆過(guò)濾器
這篇文章主要介紹了用Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的布隆過(guò)濾器,布隆過(guò)濾器是1970年由布隆提出的,它實(shí)際上是一個(gè)很長(zhǎng)的二進(jìn)制向量和一系列隨機(jī)映射函數(shù),布隆過(guò)濾器可以用于檢索一個(gè)元素是否在一個(gè)集合中,需要的朋友可以參考下2023-12-12
Java?中向?Arraylist?添加對(duì)象的示例代碼
本文介紹了如何在 Java 中向 ArrayList 添加對(duì)象,并提供了示例和注意事項(xiàng),通過(guò)掌握這些知識(shí),讀者可以在自己的 Java 項(xiàng)目中有效地使用 ArrayList 來(lái)存儲(chǔ)和操作對(duì)象,需要的朋友可以參考下2023-11-11
Java數(shù)據(jù)類型轉(zhuǎn)換的示例詳解
Java程序中要求參與的計(jì)算的數(shù)據(jù),必須要保證數(shù)據(jù)類型的一致性,如果數(shù)據(jù)類型不一致將發(fā)生類型的轉(zhuǎn)換。本文將通過(guò)示例詳細(xì)說(shuō)說(shuō)Java中數(shù)據(jù)類型的轉(zhuǎn)換,感興趣的可以了解一下2022-10-10
java集合中HashSet LinkedHashSet TreeSet三者異同面試精講
這篇文章主要為大家介紹了java集合中HashSet LinkedHashSet TreeSet三者異同面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
Nacos+Spring Cloud Gateway動(dòng)態(tài)路由配置實(shí)現(xiàn)步驟
Nacos最近項(xiàng)目一直在使用,本文通過(guò)gateway、nacos-consumer、nacos-provider三個(gè)簡(jiǎn)單模塊來(lái)展示:Nacos下動(dòng)態(tài)路由配置,,感興趣的小伙伴們可以參考一下2021-08-08
SpringBoot通過(guò)注解注入Bean的幾種方式解析
這篇文章主要為大家介紹了SpringBoot注入Bean的幾種方式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-03-03

