Spring Bean初始化及@PostConstruc執(zhí)行順序示例詳解
1. Bean初始化執(zhí)行順序
構造函數(shù) - 首先調(diào)用Bean的構造函數(shù)
依賴注入 - 完成所有依賴項的注入(@Autowired等)
@PostConstruct方法 - 執(zhí)行帶有
@PostConstruct注解的方法InitializingBean的afterPropertiesSet() - 如果Bean實現(xiàn)了
InitializingBean接口自定義init方法 - 執(zhí)行通過
@Bean(initMethod="...")或XML配置中init-method指定的方法
@Component
public class ExampleBean implements InitializingBean {
public ExampleBean() {
System.out.println("1. 構造函數(shù)");
}
@Autowired
public void setDependency(SomeDependency dep) {
System.out.println("2. 依賴注入");
}
@PostConstruct
public void postConstruct() {
System.out.println("3. @PostConstruct方法");
}
@Override
public void afterPropertiesSet() {
System.out.println("4. InitializingBean的afterPropertiesSet()");
}
@Bean(initMethod = "customInit")
public void customInit() {
System.out.println("5. 自定義init方法");
}
}2. 成員變量初始化順序
在Java中,類的成員變量(非靜態(tài)成員變量)的初始化時機取決于其定義方式(直接賦值、構造器賦值、初始化塊等)以及是否涉及依賴注入(如Spring框架)。
2.1 普通Java類(非Spring環(huán)境)
成員變量的初始化順序和時機如下:
(1) 默認初始化(即初始分配內(nèi)存)
時機:對象實例化時(
new關鍵字調(diào)用構造器之前)。規(guī)則:所有成員變量先被賦予默認值(
int→0,boolean→false,引用類型→null等)。
(2) 顯式初始化
時機:緊隨默認初始化之后,按代碼中的聲明順序執(zhí)行。
方式:
直接賦值:
public class MyClass {
private int a = 10; // 顯式賦值
private String s = "hello"; // 顯式賦值
}- 初始化塊(代碼塊):
public class MyClass {
private int x;
{
x = 20; // 初始化塊賦值
}
}(3) 構造器初始化
時機:在顯式初始化之后,構造器最后執(zhí)行。
特點:構造器中的賦值會覆蓋之前的默認值或顯式賦值。
public class MyClass {
private int value;
public MyClass() {
this.value = 30; // 構造器賦值
}
}(4)完整順序
默認值 → 顯式賦值/初始化塊 → 構造器賦值
2.2 Spring管理的Bean(依賴注入場景)
在Spring中,成員變量的初始化分為依賴注入和普通成員變量初始化兩部分:
(1) 普通成員變量
初始化規(guī)則與普通Java類一致(默認值 → 顯式賦值 → 構造器)。
示例:
@Component
public class MyBean {
private int count = 100; // 顯式賦值(Spring無關)
public MyBean() {
this.count = 200; // 構造器覆蓋
}
}(2) 依賴注入的成員變量
時機:在Bean實例化后,由Spring容器通過反射或Setter方法注入。
字段注入(
@Autowired):
在構造器和顯式賦值之后,通過反射直接注入。@Component public class MyBean { @Autowired private Dependency dependency; // Spring在對象構造后注入 }構造器注入:
在實例化時通過構造器參數(shù)注入(等同于普通Java的構造器賦值)。@Component public class MyBean { private final Dependency dependency; public MyBean(Dependency dependency) { this.dependency = dependency; // 構造時注入 } }
(3) 生命周期回調(diào)的影響
@PostConstruct方法會在依賴注入完成后執(zhí)行,此時所有成員變量(包括注入的依賴)已就緒:@Component public class MyBean { @Autowired private Dependency dependency; @PostConstruct public void init() { System.out.println(dependency); // 依賴已注入 } }
(4)關鍵區(qū)別總結
| 場景 | 成員變量初始化時機 |
|---|---|
| 普通Java類 | 默認值 → 顯式賦值/初始化塊 → 構造器賦值 |
| Spring Bean(字段注入) | 默認值 → 顯式賦值 → 構造器 → 依賴注入 → @PostConstruct |
| Spring Bean(構造器注入) | 與普通Java類相同,依賴通過構造器參數(shù)傳入 |
2.3 final成員變量
必須在聲明時、初始化塊或構造器中賦值,否則編譯錯誤。
public class MyClass {
private final int x = 10; // 聲明時賦值
private final int y;
{ y = 20; } // 初始化塊賦值
private final int z;
public MyClass() {
z = 30; // 構造器賦值
}
}2.4 常見面試問題
Q1: 為什么構造器里的賦值能覆蓋顯式賦值?
因為構造器是最后執(zhí)行的,可以修改之前的值。
Q2: 以下代碼的輸出是什么?
public class Test {
private int x = 10;
{ x = 20; }
public Test() {
System.out.println(x);
x = 30;
}
public static void main(String[] args) {
new Test(); // 輸出?
}
}
--
答案:20(顯式賦值和初始化塊先執(zhí)行,構造器最后執(zhí)行)。到此這篇關于Spring Bean初始化及@PostConstruc執(zhí)行順序的文章就介紹到這了,更多相關Spring Bean初始化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
spring-Kafka中的@KafkaListener深入源碼解讀
本文主要通過深入了解源碼,梳理從spring啟動到真正監(jiān)聽kafka消息的這套流程,從spring啟動開始處理@KafkaListener,本文結合實例流程圖給大家講解的非常詳細,需要的朋友參考下2023-02-02
使用Spring?Retry實現(xiàn)業(yè)務異常重試
在系統(tǒng)中經(jīng)常遇到業(yè)務重試的邏輯,比如三方接口調(diào)用,timeout重試三遍,異常處理重試的兜底邏輯等,本文給大家介紹一下如何使用Spring?Retry優(yōu)雅的實現(xiàn)業(yè)務異常重試,需要的朋友可以參考下2024-01-01
Java8 中使用Stream 讓List 轉 Map使用問題小結
這篇文章主要介紹了Java8 中使用Stream 讓List 轉 Map使用總結,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-06-06

