1. 前言
隨著我們專案的不斷迭代 Bean 的數量會大大增加,如果都在啟動時進行初始化會非常耗時。Spring Boot 允許延遲初始化應用程式, 也就是根據需要初始化 Spring Bean,而不是在 Spring Boot 啟動時建立所有的 Bean。這樣的就可以減少應用程式啟動花費的時間。延遲初始化通常又被稱為“懶載入”。
2. 延遲初始化
Spring Boot 中的延遲初始化可分為全域性延遲初始化和區域性初始化。
注意:以下特性在 Spring Boot 2.2.x 中存在
2.1 全域性初始化
全域性初始化我們可以通過程式設計的方式來實現,需要我們來改變 Spring Boot Main方法的寫法。
通常我們的 Main 方法是這樣的,注意這裡還沒宣告全域性懶載入:
/**
* @author felord.cn
* @since 2020/3/31 22:53
*/
@SpringBootApplication
public class DemoSpringbootApplication {
@Lazy
public static void main(String[] args) {
SpringApplication.run(DemoSpringbootApplication.class,args);
}
}
複製程式碼
全域性懶載入寫法一:
/**
* @author felord.cn
* @since 2020/3/31 22:53
*/
@SpringBootApplication
public class DemoSpringbootApplication {
@Lazy
public static void main(String[] args) {
SpringApplication sa = new SpringApplication(DemoSpringbootApplication.class);
sa.setLazyInitialization(true);
sa.run(args);
}
}
複製程式碼
全域性懶載入寫法二:
/**
* @author felord.cn
* @since 2020/3/31 22:53
*/
@SpringBootApplication
public class DemoSpringbootApplication {
@Lazy
public static void main(String[] args) {
SpringApplicationBuilder sab = new SpringApplicationBuilder(DemoSpringbootApplication.class);
sab.lazyInitialization(true).run(args);
}
}
複製程式碼
上面的寫法一和寫法二都是我們通過程式設計方式定製一些 Spring Boot 特性,大多數都是全域性特性。包括本文講述的 “懶載入”。
我們還可以採取更簡單的配置檔案(application.properties)的方式來配置延遲初始化:
# 預設是關閉的 false
spring.main.lazy-initialization=true
複製程式碼
當我們開啟了全域性的延遲載入後,在 Web 應用程式中將導致許多與 Web 相關的 Bean 直到收到第一次 HTTP 請求後才被初始化。
控制器:
/**
* @author felord.cn
* @since 2020/3/31 23:31
*/
@RestController
@RequestMapping
public class FooController {
private FooService fooService;
public FooController(FooService fooService) {
System.out.println("fooController init...")
this.fooService = fooService;
}
@GetMapping("/req")
public Map<String, String> demo() {
System.out.println("Preparing HTTP request...");
return fooService.response();
}
}
複製程式碼
服務層:
/**
* @author felord.cn
* @since 2020/3/31 23:36
*/
@Service
public class FooService {
public FooService() {
System.out.println("fooService init ...");
}
public Map<String, String> response() {
Map<String, String> map = new HashMap<>();
map.put("msg","from fooService");
return map;
}
}
複製程式碼
呼叫 /req
介面後我們發現,不單單 FooController
和 FooService
在第一次呼叫初始化,連 Spring MVC 核心 DispatcherServlet
都是第一次呼叫時初始化。
2.2 區域性初始化
如果我們不想讓全域性延遲初始化作用於個別的 Bean 怎麼辦?我們可以在這個 Bean 上宣告註解 @Lazy(value = false)
即可。你可以改寫 2.1 的程式碼自己試一試。這個 @Lazy
作用於區域性,並通過布林值 value
來控制是否延遲初始化。情況是這樣的:
- 當我們宣告全域性延遲載入時,
@Lazy(value = false)
標記的 Bean 會被立即載入。 - 當我們宣告全域性不延遲載入時,
@Lazy
標記的 Bean 會被延遲載入。
請注意:
@Lazy
會影響到@Configuration
下宣告的 Bean
3. 注意事項
延遲初始化的缺點是,如果錯誤配置的 Bean 是延遲初始化的,則在啟動期間將不再發生故障,並且只有在初始化 Bean 時錯誤才會暴露出來,所以一定要經過嚴格的測試。
同時還必須注意確保 JVM 具有足夠的記憶體來容納所有應用程式的 Bean,而不僅僅是啟動期間初始化的 Bean。因此建議在啟用延遲初始化之前先對 JVM 的堆大小進行必要的檢測和微調以保證不會溢位。
那些初始化耗時,具有複雜邏輯,而且不是啟動的必要選擇的 Bean 應當被延遲初始化。
4. 總結
今天對 Spring Boot 如何進行延遲初始化進行了講解,同時也說明了一些注意事項。間接地也對 Main 方法的幾種姿勢也進行了展示,希望對你的實際開發有所幫助。關注公眾號:Felordcn 將自動獲取技術乾貨資料。