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