目錄
- Spring Boot 原理
- 配置優先級
- Bean 管理
- 獲取 Bean
- Bean 的作用域
- 第三方 Bean
- Spring Boot 底層原理
- 起步依賴
- 自動配置
- 核心原理
- 實例說明
- 例 1:自定義一個 “日志 starter”
- 例 2:SpringBoot 自帶的 spring-boot-starter-web
- 關鍵總結
Spring Boot 原理
配置優先級
Spring Boot 中支持三種格式的配置文件:
-
application.properties
server.port=8081
-
application.yml
server:port: 8082
-
application.yaml
server:port: 8083
在代碼中配置這三個文件,運行程序的結果如下;
Tomcat 服務器在 8081 端口運行
如果只配置 application.yml 和 application.yaml,程序運行結果如下:
Tomcat 服務器在 8082 端口運行
通過測試同一屬性在三個文件中的配置,得出優先級:properties 最高,yml 次之,yaml 最低。
Spring Boot 除了支持配置文件屬性配置,還支持 Java 系統屬性和命令行參數的方式進行屬性配置
- Java系統屬性:
-Dserver.port=9000
- 命令行參數:
--server.port=9001
命令行參數優先級高于 Java 系統屬性。
在 Spring Boot 項目打包后,若需配置屬性(如端口號等),可通過 Java 系統屬性和命令行參數兩種方式進行,具體操作如下:
-
項目打包前提
-
打包需執行 Maven 的
package
生命周期,生成可運行的 jar 包。 -
注意:Spring Boot 項目打包必須依賴
spring-boot-maven-plugin
插件,基于官方骨架創建的項目會自動引入該插件,無需手動添加。
-
-
運行打包后的 jar 包
-
基本命令:
java -jar 項目名.jar
-
(例如:
java -jar spring-boot-web-config.jar
,可通過tab
鍵自動補全 jar 包名稱)
-
-
配置 Java 系統屬性
-
格式:在
java
命令后、-jar
之前,使用-Dkey=value
格式配置。 -
示例:配置 Tomcat 端口號為 9000
java -Dserver.port=9000 -jar spring-boot-web-config.jar
-
-
配置命令行參數
-
格式:在 jar 包名稱之后,使用
--key=value
格式配置。 -
示例:配置 Tomcat 端口號為 10010
java -jar spring-boot-web-config.jar --server.port=10010
-
五種配置方式的優先級:從高到低依次為命令行參數、Java 系統屬性、properties 配置文件、yml 配置文件、yaml 配置文件。
Bean 管理
獲取 Bean
默認情況下,Spring 項目啟動時,會把 Bean 都創建好放在 IOC 容器中,如果想要主動獲取這些 Bean,可以通過以下方式:
- 根據 name 獲取 Bean:
Object getBean(String name)
- 根據類型獲取 Bean:
<T> T getBean(Class<T> requiredType)
- 根據 name 獲取 Bean(帶類型轉換):
<T> T getBean(String name, Class<T> requiredType)
在測試類中加入以下代碼進行獲取 Bean 的測試:
@Autowired
// 獲取ApplicationContext對象
private ApplicationContext applicationContext;
@Test
public void testGetBean(){// 根據Bean的名稱獲取DeptController bean1 = (DeptController) applicationContext.getBean("deptController");System.out.println(bean1);// 根據Bean的類型獲取DeptController bean2 = applicationContext.getBean(DeptController.class);System.out.println(bean2);// 根據Bean的名稱和類型獲取DeptController bean3 = applicationContext.getBean("deptController", DeptController.class);System.out.println(bean3);
}
測試運行結果如下:
三次調用 getBean 方法獲取同一 bean 對象,其地址值相同,說明默認情況下 bean 是單例的。
Spring 項目啟動時創建所有 bean 對象并放在 IOC 容器中,這僅針對默認情況下單例且非延遲加載的 bean,bean 的創建時間還受作用域和延遲初始化影響
Bean 的作用域
bean 是單例還是多例取決于其作用域,Spring 中 bean 支持五種作用域,重點關注前兩種,后三種在 web 環境生效:
作用域 | 說明 |
---|---|
singleton | 在整個 Spring 容器中,同名稱的 bean 對象只有一個實例,即單例,是作用域的默認值 |
prototype | 代表非單例,每一次使用該 bean 對象時,都會創建一個新的實例對象 |
request | 代表每一次請求對應一個實例對象 |
session | 代表每一次會話對應一個新的實例對象 |
application | 代表每一個應用對應一個實例對象 |
默認情況下,未設置作用域的 bean 是單例的,在 Spring 項目啟動、IOC 容器創建時就會實例化并放到容器中,多次獲取的是同一個對象。
設置 bean 作用域的方式:可以借助 Spring 中的 @Scope 注解來配置 bean 的作用域。
在要獲取 Bean 的類上添加 @Scope("prototype")
,運行前面的測試代碼,結果如下:
延遲初始化注解 @lazy
:在類上添加 @lazy
注解后,bean 會延遲初始化,延遲到第一次使用的時候實例化。
注意事項:
- 默認作用域為 singleton,默認單例 bean 在容器啟動時創建,可通過
@lazy
延遲到第一次使用時創建 - prototype 非單例 bean 每次使用都會創建新實例
第三方 Bean
第三方 Bean 配置的必要性:項目中引入的第三方依賴提供的類(如 dom4j 中的 SAXReader),若每次使用都新建對象會耗費資源,需交給 Spring 的 IOC 容器管理,通過依賴注入使用。
第三方 Bean 配置的特殊之處:第三方類是只讀的,無法直接在類上添加 @Component 及其衍生注解聲明為 bean,需使用 @Bean 注解。
@Bean 注解的使用方法:在方法上添加 @Bean 注解,方法返回值為要管理的第三方 Bean 對象,Spring 會將方法返回值交給 IOC 容器管理,后續可通過 @Autowired 注入使用。
第三方 Bean 配置的位置:建議單獨定義配置類(用 @Configuration 標識),在配置類中集中配置第三方 bean。
第三方 Bean 的名稱規則:可通過 @Bean 的 name 或 value 屬性指定名稱,二者互為別名;未指定時,默認名稱為方法名。
第三方 Bean 聲明時的依賴注入:在定義第三方 bean 的方法中聲明對應類型的形參,Spring 容器會根據類型自動裝配 IOC 容器中的對應 Bean 對象。
Spring Boot 底層原理
Spring Boot 簡化開發的原因:底層提供起步依賴和自動配置兩個重要功能。起步依賴簡化 pom 文件依賴配置,解決 Spring 框架依賴配置繁瑣問題;自動配置簡化框架使用時 Bean 的聲明和配置,引入起步依賴后常見配置已存在,可直接使用。
起步依賴
以 Web 程序開發為例,使用 Spring 框架需引入多個依賴且版本需匹配,而使用 Spring Boot 只需引入對應的起步依賴(如 web 開發的 spring-boot-starter-web,aop 開發的 spring-boot-starter-aop)。其原理是 Maven 的依賴傳遞,起步依賴集成了開發所需的常見依賴,引入一個起步依賴后,其他依賴會通過依賴傳遞自動引入(若 A 依賴 B,B 依賴 C,C 依賴 D,引入 A 則 B、C、D 也會被引入)。
自動配置
自動配置的定義:指 Spring Boot 項目啟動時,除了用戶自己定義的 Bean 對象外,Spring Boot 會自動創建一些內置的配置類及 Bean 對象并放入 IOC 容器,使用戶在開發時無需手動聲明即可直接使用,簡化開發,省去繁瑣配置。
通過啟動 Spring Boot 工程,在控制臺的 Bean 中可查看所有 Bean 對象及配置類,包括用戶自己定義的和 Spring Boot 自動加載的配置類及其生成的 Bean 對象
核心原理
自動配置的實現依賴 3 個關鍵機制:@EnableAutoConfiguration 注解、SPI 機制(META-INF/spring.factories)、條件注解(@Conditional)。三者協同工作,流程如下:
- 觸發點:@SpringBootApplication 注解
SpringBoot 項目的啟動類通常標注@SpringBootApplication
,它是一個組合注解,包含 3 個核心注解:
@SpringBootConfiguration
:標記當前類為配置類(類似@Configuration
)。@ComponentScan
:默認掃描啟動類所在包及其子包(但自動配置不依賴它,而是通過其他機制加載外部包的 Bean)。@EnableAutoConfiguration
:自動配置的 “開關”,正是這個注解觸發了后續的自動配置流程。
- 核心:@EnableAutoConfiguration 的作用
@EnableAutoConfiguration
通過@Import(AutoConfigurationImportSelector.class)
導入了AutoConfigurationImportSelector
類,這個類是自動配置的 “核心執行者”,主要做兩件事:
- 加載候選配置類:掃描類路徑下所有
META-INF/spring.factories
文件,讀取其中org.springframework.boot.autoconfigure.EnableAutoConfiguration
對應的配置類全類名(這些是 “候選自動配置類”)。 - 篩選有效配置類:通過
spring.factories
加載的候選配置類會經過條件注解(如@ConditionalOnClass
)的篩選,只有滿足條件的配置類才會被真正加載到 IOC 容器。
- SPI 機制:META-INF/spring.factories 的作用
META-INF/spring.factories
是 Java 的 SPI(Service Provider Interface)機制在 SpringBoot 中的應用,用于聲明 “自動配置類” 的位置。
格式如下(key 固定為org.springframework.boot.autoconfigure.EnableAutoConfiguration
,value 為自動配置類的全類名列表):
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAutoConfiguration,\
com.example.OtherAutoConfiguration
當項目啟動時,AutoConfigurationImportSelector
會讀取所有依賴中的spring.factories
,收集所有聲明的自動配置類,作為候選者。
- 條件注解:篩選有效的配置類
候選配置類不會全部生效,需要通過條件注解判斷是否滿足生效條件。常見的條件注解有:
@ConditionalOnClass
:類路徑下存在指定類時,配置類才生效(如引入spring-web
依賴后,DispatcherServlet.class
存在,Web 相關配置才生效)。@ConditionalOnMissingBean
:容器中不存在指定 Bean 時,配置類才生效(允許開發者自定義 Bean 覆蓋默認配置)。@ConditionalOnProperty
:配置文件中存在指定屬性時生效(如server.port
配置觸發端口綁定)。
只有滿足所有條件的配置類,才會被 Spring 實例化,其內部定義的 Bean 才會被注冊到 IOC 容器。
總結流程:
- 啟動類標注
@SpringBootApplication
,觸發@EnableAutoConfiguration
。 AutoConfigurationImportSelector
掃描所有META-INF/spring.factories
,收集候選自動配置類。- 候選配置類通過條件注解篩選,保留有效配置類。
- 有效配置類被加載,其內部的 Bean(如
DataSource
、DispatcherServlet
)被注冊到 IOC 容器。
實例說明
下面通過兩個例子(自定義 starter 和 SpringBoot 自帶 starter)直觀理解自動配置。
例 1:自定義一個 “日志 starter”
假設我們要開發一個my-log-starter
,功能是:引入后自動配置一個LogService
Bean,用于打印日志。
步驟 1:定義核心 Bean 和配置類
-
LogService:需要被自動配置的 Bean。
public class LogService {public void log(String message) {System.out.println("[MyLog] " + message);} }
-
LogAutoConfiguration:自動配置類,負責注冊
LogService
。@Configuration // 標記為配置類 @ConditionalOnClass(LogService.class) // 類路徑存在LogService時生效 public class LogAutoConfiguration {// 注冊LogService到IOC容器@Bean@ConditionalOnMissingBean // 若用戶自定義了LogService,則不使用默認的public LogService logService() {return new LogService();} }
步驟 2:通過 spring.factories 聲明自動配置類
在src/main/resources
下創建META-INF/spring.factories
,聲明LogAutoConfiguration
為候選配置類:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.log.LogAutoConfiguration
步驟 3:使用 starter
-
其他項目引入
my-log-starter
依賴后,啟動項目時:
AutoConfigurationImportSelector
讀取spring.factories
,發現LogAutoConfiguration
。- 檢查到類路徑存在
LogService.class
(依賴已引入),且容器中沒有自定義的LogService
,滿足條件。 LogAutoConfiguration
生效,logService()
方法被執行,LogService
Bean 被注冊到 IOC 容器。
-
開發者可直接注入使用:
@RestController public class TestController {@Autowiredprivate LogService logService; // 直接使用自動配置的Bean@GetMapping("/test")public String test() {logService.log("測試日志"); // 輸出:[MyLog] 測試日志return "ok";} }
例 2:SpringBoot 自帶的 spring-boot-starter-web
引入spring-boot-starter-web
后,SpringBoot 會自動配置 Web 開發所需的核心組件(如 Tomcat、DispatcherServlet),原理如下:
- 依賴引入:
starter-web
包含spring-web
、spring-webmvc
、tomcat-embed-core
等依賴。 - 自動配置類:
spring-boot-autoconfigure
包的META-INF/spring.factories
中聲明了DispatcherServletAutoConfiguration
、TomcatAutoConfiguration
等配置類。 - 條件判斷:
TomcatAutoConfiguration
通過@ConditionalOnClass(Tomcat.class)
判斷:因引入了tomcat-embed-core
,Tomcat 類存在,配置生效,自動啟動內嵌 Tomcat。DispatcherServletAutoConfiguration
通過@ConditionalOnClass(DispatcherServlet.class)
判斷:因引入spring-webmvc
,DispatcherServlet 類存在,配置生效,注冊DispatcherServlet
到容器。
- 最終效果:開發者無需手動配置 Tomcat 和 DispatcherServlet,引入依賴即可開發 Web 接口。
關鍵總結
- 自動配置的核心是:通過 @EnableAutoConfiguration 觸發,SPI 機制加載候選配置類,條件注解篩選有效配置類。
- 開發者可通過自定義 starter(含
spring.factories
和自動配置類)實現自動配置,也可通過@ConditionalOnMissingBean
等注解覆蓋默認配置。 - SpringBoot 的 starter(如
web
、data-jpa
)都是基于此原理實現,極大簡化了配置流程。