目錄
1. Bean初始化執行順序
2. 成員變量初始化順序
2.1?普通Java類(非Spring環境)
(1) 默認初始化(即初始分配內存)
(2) 顯式初始化
(3) 構造器初始化
(4)完整順序
2.2 Spring管理的Bean(依賴注入場景)
(1) 普通成員變量
(2) 依賴注入的成員變量
(3) 生命周期回調的影響
(4)關鍵區別總結
2.3 final?成員變量?
2.4 常見面試問題
1. Bean初始化執行順序
-
構造函數?- 首先調用Bean的構造函數
-
依賴注入?- 完成所有依賴項的注入(@Autowired等)
-
@PostConstruct方法?- 執行帶有
@PostConstruct
注解的方法 -
InitializingBean的afterPropertiesSet()?- 如果Bean實現了
InitializingBean
接口 -
自定義init方法?- 執行通過
@Bean(initMethod="...")
或XML配置中init-method
指定的方法
@Component
public class ExampleBean implements InitializingBean {public ExampleBean() {System.out.println("1. 構造函數");}@Autowiredpublic void setDependency(SomeDependency dep) {System.out.println("2. 依賴注入");}@PostConstructpublic void postConstruct() {System.out.println("3. @PostConstruct方法");}@Overridepublic void afterPropertiesSet() {System.out.println("4. InitializingBean的afterPropertiesSet()");}@Bean(initMethod = "customInit")public void customInit() {System.out.println("5. 自定義init方法");}
}
2. 成員變量初始化順序
在Java中,類的成員變量(非靜態成員變量)的初始化時機取決于其定義方式(直接賦值、構造器賦值、初始化塊等)以及是否涉及依賴注入(如Spring框架)。
2.1?普通Java類(非Spring環境)
成員變量的初始化順序和時機如下:
(1) 默認初始化(即初始分配內存)
-
時機:對象實例化時(
new
關鍵字調用構造器之前)。 -
規則:所有成員變量先被賦予默認值(
int
→0
,boolean
→false
,引用類型→null
等)。
(2) 顯式初始化
-
時機:緊隨默認初始化之后,按代碼中的聲明順序執行。
-
方式:
-
直接賦值:
-
public class MyClass {private int a = 10; // 顯式賦值private String s = "hello"; // 顯式賦值
}
- 初始化塊(代碼塊):
public class MyClass {private int x;{x = 20; // 初始化塊賦值}
}
(3) 構造器初始化
-
時機:在顯式初始化之后,構造器最后執行。
-
特點:構造器中的賦值會覆蓋之前的默認值或顯式賦值。
public class MyClass {private int value;public MyClass() {this.value = 30; // 構造器賦值}
}
(4)完整順序
默認值 → 顯式賦值/初始化塊 → 構造器賦值
2.2 Spring管理的Bean(依賴注入場景)
在Spring中,成員變量的初始化分為依賴注入和普通成員變量初始化兩部分:
(1) 普通成員變量
-
初始化規則與普通Java類一致(默認值 → 顯式賦值 → 構造器)。
-
示例:
@Component
public class MyBean {private int count = 100; // 顯式賦值(Spring無關)public MyBean() {this.count = 200; // 構造器覆蓋}
}
(2) 依賴注入的成員變量
-
時機:在Bean實例化后,由Spring容器通過反射或Setter方法注入。
-
字段注入(
@Autowired
):
在構造器和顯式賦值之后,通過反射直接注入。@Component public class MyBean {@Autowiredprivate Dependency dependency; // Spring在對象構造后注入 }
-
構造器注入:
在實例化時通過構造器參數注入(等同于普通Java的構造器賦值)。@Component public class MyBean {private final Dependency dependency;public MyBean(Dependency dependency) {this.dependency = dependency; // 構造時注入} }
-
(3) 生命周期回調的影響
-
@PostConstruct
方法會在依賴注入完成后執行,此時所有成員變量(包括注入的依賴)已就緒:@Component public class MyBean {@Autowiredprivate Dependency dependency;@PostConstructpublic void init() {System.out.println(dependency); // 依賴已注入} }
(4)關鍵區別總結
場景 | 成員變量初始化時機 |
---|---|
普通Java類 | 默認值 → 顯式賦值/初始化塊 → 構造器賦值 |
Spring Bean(字段注入) | 默認值 → 顯式賦值 → 構造器 → 依賴注入 →?@PostConstruct |
Spring Bean(構造器注入) | 與普通Java類相同,依賴通過構造器參數傳入 |
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: 為什么構造器里的賦值能覆蓋顯式賦值?
因為構造器是最后執行的,可以修改之前的值。
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(顯式賦值和初始化塊先執行,構造器最后執行)。