?Spring?中?Bean?的生命周期詳解
前言
Java 中的公共類(lèi)稱(chēng)之為 Bean 或 Java Bean,而 Spring 中的 Bean 指的是將對(duì)象的生命周期,交個(gè) Spring IoC 容器來(lái)管理的對(duì)象。所以 Spring 中的 Bean 對(duì)象在使用時(shí),無(wú)需通過(guò) new 來(lái)創(chuàng)建對(duì)象,只需要通過(guò) DI(依賴(lài)注入),從 Spring 中取出要使用的對(duì)象即可。 那么 Spring 中,Bean 的生命周期又有哪些呢?接下來(lái),我們一起來(lái)看。
1.Bean 生命周期
Spring 中 Bean 的生命周期是指:Bean 在 Spring(IoC)中從創(chuàng)建到銷(xiāo)毀的整個(gè)過(guò)程。
Spring 中 Bean 的生命周期主要包含以下 5 部分:
- 實(shí)例化:為 Bean 分配內(nèi)存空間;
- 設(shè)置屬性:將當(dāng)前類(lèi)依賴(lài)的 Bean 屬性,進(jìn)行注入和裝配;
- 初始化:
- 執(zhí)行各種通知;
- 執(zhí)行初始化的前置方法;
- 執(zhí)行初始化方法;
- 執(zhí)行初始化的后置方法。
- 使用 Bean:在程序中使用 Bean 對(duì)象;
- 銷(xiāo)毀 Bean:將 Bean 對(duì)象進(jìn)行銷(xiāo)毀操作。
以上生命周期中,需要注意的是:“實(shí)例化”和“初始化”是兩個(gè)完全不同的過(guò)程,千萬(wàn)不要搞混,實(shí)例化只是給 Bean 分配了內(nèi)存空間,而初始化則是將程序的執(zhí)行權(quán),從系統(tǒng)級(jí)別轉(zhuǎn)換到用戶(hù)級(jí)別,并開(kāi)始執(zhí)行用戶(hù)添加的業(yè)務(wù)代碼。
2.代碼演示
接下來(lái)我們使用代碼的方式在 Spring Boot 中,給大家演示一下 Bean 的生命周期。
PS:因?yàn)?Spring Boot 是基于 Spring 創(chuàng)建的,所以 Bean 在 Spring 或 Spring Boot 中的行為都是一致的,而 Spring Boot 又是目前主流的框架,所以本文使用 Spring Boot 來(lái)演示 Bean 的生命周期。
首先,我們創(chuàng)建一個(gè) Bean 對(duì)象,起名為 BeanLifeComponent(類(lèi)命無(wú)所謂,可隨意指定),它的具體實(shí)現(xiàn)代碼如下:
import org.springframework.beans.factory.BeanNameAware; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @Component public class BeanLifeComponent implements BeanNameAware { public void setBeanName(String s) { System.out.println("執(zhí)行 BeanName 的通知方法"); } @PostConstruct public void postConstruct() { System.out.println("執(zhí)行初始化方法"); } public void use() { System.out.println("使用 Bean"); } @PreDestroy public void preDestroy() { System.out.println("執(zhí)行銷(xiāo)毀方法"); } }
然后,我們?cè)賱?chuàng)建一個(gè) MyBeanPostProcessor 類(lèi)(類(lèi)命無(wú)所謂,可隨意指定),來(lái)實(shí)現(xiàn)初始化的前置方法和初始化的后置方法,
具體實(shí)現(xiàn)代碼如下:
import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.stereotype.Component; @Component public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (beanName.equals("beanLifeComponent")) { System.out.println("執(zhí)行初始化前置方法"); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (beanName.equals("beanLifeComponent")) { System.out.println("執(zhí)行初始化后置方法"); } return bean; } }
為什么要?jiǎng)?chuàng)建一個(gè)單獨(dú)的類(lèi)來(lái)執(zhí)行初始化的前置方法和初始化的后置方法呢? 這是因?yàn)槌跏蓟那爸梅椒ê秃笾梅椒ㄊ菫樗?Bean 服務(wù)的,而非為某一個(gè) Bean 服務(wù)的,所以這兩個(gè)方法不能寫(xiě)在某個(gè)具體的 Bean 中,否則(這兩個(gè)方法)不會(huì)執(zhí)行。 最后,在 Spring Boot 的啟動(dòng)類(lèi)中獲取 Bean,
具體實(shí)現(xiàn)代碼如下:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { // 得到上下文對(duì)象,并啟動(dòng) Spring Boot 項(xiàng)目 ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args); // 獲取 Bean BeanLifeComponent component = context.getBean(BeanLifeComponent.class); // 使用 Bean component.use(); // 停止 Spring Boot 項(xiàng)目 context.close(); } }
以上程序最終的執(zhí)行結(jié)果如下圖所示:
從上面的執(zhí)行結(jié)果可以看出,代碼執(zhí)行順序符合 Bean 生命周期的執(zhí)行順序:
- 實(shí)例化:為 Bean 分配內(nèi)存空間;
- 設(shè)置屬性:將當(dāng)前類(lèi)依賴(lài)的 Bean 屬性,進(jìn)行注入和裝配;
- 初始化:
- 執(zhí)行各種通知;
- 執(zhí)行初始化的前置方法;
- 執(zhí)行初始化方法;
- 執(zhí)行初始化的后置方法。
- 使用 Bean:在程序中使用 Bean 對(duì)象;
- 銷(xiāo)毀 Bean:將 Bean 對(duì)象進(jìn)行銷(xiāo)毀操作。
那么問(wèn)題來(lái)了,能不能先執(zhí)行初始化再執(zhí)行設(shè)置屬性呢?也就是將生命周期中的步驟 2 和步驟 3 的執(zhí)行順序交換一下? 答案是否定的。想象一個(gè)場(chǎng)景,如果在初始化方法中要用到被注入對(duì)象的某個(gè)方法,
比如以下代碼:
@Controller public class UserController { @Resource private UserService userService; @PostConstruct // 初始化方法 public void postConstruct() { userService.sayHi(); } }
此時(shí)如果先執(zhí)行步驟 2,先將 UserService 注入到當(dāng)前類(lèi),再調(diào)用步驟 3 執(zhí)行初始化,那么程序的執(zhí)行是正常的。然而如果將交互步驟 2 和步驟 3 的執(zhí)行順序,那么程序執(zhí)行就會(huì)報(bào)錯(cuò)(空指針異常),所以 Bean 的生命周期的順序必須是:
1.實(shí)例化:為 Bean 分配內(nèi)存空間; 2.設(shè)置屬性:將當(dāng)前類(lèi)依賴(lài)的 Bean 屬性,進(jìn)行注入和裝配; 3.初始化:
- 執(zhí)行各種通知;
- 執(zhí)行初始化的前置方法;
- 執(zhí)行初始化方法;
- 執(zhí)行初始化的后置方法。 4.使用 Bean:在程序中使用 Bean 對(duì)象; 5.銷(xiāo)毀 Bean:將 Bean 對(duì)象進(jìn)行銷(xiāo)毀操作。
總結(jié)
Bean 的生命周期指的是 Bean 在 Spring(IoC)中從創(chuàng)建到銷(xiāo)毀的整個(gè)過(guò)程。Bean 的生命周期主要包含以下 5 個(gè)流程:
1.實(shí)例化:為 Bean 分配內(nèi)存空間;
2.設(shè)置屬性:將當(dāng)前類(lèi)依賴(lài)的 Bean 屬性,進(jìn)行注入和裝配;
3.初始化:
- 執(zhí)行各種通知;
- 執(zhí)行初始化的前置方法;
- 執(zhí)行初始化方法;
- 執(zhí)行初始化的后置方法。 4.使用 Bean:在程序中使用 Bean 對(duì)象; 5.銷(xiāo)毀 Bean:將 Bean 對(duì)象進(jìn)行銷(xiāo)毀操作。
到此這篇關(guān)于 Spring 中 Bean 的生命周期詳解的文章就介紹到這了,更多相關(guān) Spring Bean 生命周期內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java使用Catcher捕獲異常的實(shí)現(xiàn)
本文主要介紹了Java使用Catcher捕獲異常的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05圖解Java經(jīng)典算法快速排序的原理與實(shí)現(xiàn)
快速排序是基于二分的思想,對(duì)冒泡排序的一種改進(jìn)。主要思想是確立一個(gè)基數(shù),將小于基數(shù)的數(shù)放到基數(shù)左邊,大于基數(shù)的數(shù)字放到基數(shù)的右邊,然后在對(duì)這兩部分進(jìn)一步排序,從而實(shí)現(xiàn)對(duì)數(shù)組的排序2022-09-09Java8優(yōu)雅的字符串拼接工具類(lèi)StringJoiner實(shí)例代碼
這篇文章主要給大家介紹了關(guān)于Java8優(yōu)雅的字符串拼接工具類(lèi)StringJoiner的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02基于Java并發(fā)容器ConcurrentHashMap#put方法解析
下面小編就為大家?guī)?lái)一篇基于Java并發(fā)容器ConcurrentHashMap#put方法解析。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06Springboot使用maven打包指定mainClass問(wèn)題
這篇文章主要介紹了Springboot使用maven打包指定mainClass問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04