SpringBoot啟動時執(zhí)行初始化操作的幾種方式
場景
項目中,經常需要在啟動過程中初始化一些數(shù)據,如從數(shù)據庫讀取一些配置初始化,或從數(shù)據庫讀取一些熱點數(shù)據到redis進行初始化緩存。
方式一:實現(xiàn)CommandLineRunner 接口重寫run方法邏輯
CommandLineRunner是Spring提供的接口,定義了一個run()方法,用于執(zhí)行初始化操作。
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class InitConfigCommand implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner:"+"{}"+"接口實現(xiàn)方式重寫");
}
}
CommandLineRunner的執(zhí)行時機為Spring beans初始化之后,因此CommandLineRunner的執(zhí)行一定是晚于@PostConstruct的。
若有多組初始化操作,則每一組操作都要定義一個CommandLineRunner派生類并實現(xiàn)run()方法。這些操作的執(zhí)行順序使用@Order(n)來設置,n為int型數(shù)據。
@Component
@Order(99)
public class CommandLineRunnerA implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("初始化:CommandLineRunnerA");
}
}
@Component
@Order(1)
public class CommandLineRunnerB implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("初始化:CommandLineRunnerB");
}
}
如上,會先執(zhí)行CommandLineRunnerB的run(),再執(zhí)行CommandLineRunnerA的run()。
@Order(n)中的n較小的會先執(zhí)行,較大的后執(zhí)行。n只要是int值即可,無需順序遞增。
方式二:實現(xiàn)ApplicationRunner接口重寫run方法邏輯
ApplicationRunner接口與CommandLineRunner接口類似,都需要實現(xiàn)run()方法。二者的區(qū)別在于run()方法的參數(shù)不同:
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
public class InitConfig implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("項目啟動初始化");
}
}
ApplicationRunner接口的run()參數(shù)為ApplicationArguments對象,因此可以獲取更多項目相關的內容。
ApplicationRunner接口與CommandLineRunner接口的調用時機也是相同的,都是Spring beans初始化之后。因此ApplicationRunner接口也使用@Order(n)來設置執(zhí)行順序。
方式三:使用@PostConstruct注解的方式
對于注入到Spring容器中的類,在其成員函數(shù)前添加@PostConstruct注解,則在執(zhí)行Spring beans初始化時,就會執(zhí)行該函數(shù)。
但由于該函數(shù)執(zhí)行時,其他Spring beans可能并未初始化完成,因此在該函數(shù)中執(zhí)行的初始化操作應當不依賴于其他Spring beans。
@Component
public class Construct {
@PostConstruct
public void doConstruct() throws Exception {
System.out.println("初始化:PostConstruct");
}
}
初始化順序
- @PostConstruct 注解方法
- CommandLineRunner接口實現(xiàn)
- ApplicationRunner接口實現(xiàn)
擴展
@PostConstruct注解使用在方法上,它可以被用來標注一個非靜態(tài)的 void 方法,這個方法會在該類被 Spring 容器初始化后立即執(zhí)行。因為它的執(zhí)行時機是在依賴注入之后,對象構造完成之后,也就是說是在@Autowired注入之后執(zhí)行。所以這里可以進行一些初始化操作,如某些需要在對象創(chuàng)建后才能進行的數(shù)據初始化操作。
需要注意以下幾點:
- @PostConstruct 只能用在方法上面,而不能用在屬性或構造函數(shù)上。
- 一個類中可以有多個使用 @PostConstruct 注解的方法,但執(zhí)行順序并不是固定的。
- @PostConstruct 注解的方法在本類中必須是無參數(shù)的,如果有參數(shù),那么這個方法不會被執(zhí)行。
- @PostConstruct 注解的方法在實現(xiàn)上可以使用任意修飾符。
假設我們有一個需要初始化數(shù)據的類:
public class InitService {
private List<String> data;
public InitService() {
this.data = Arrays.asList("A", "B", "C");
}
@PostConstruct
public void init() {
data.add("D");
}
public List<String> getData() {
return this.data;
}
}
當我們實例化 InitService 時,構造函數(shù)會為 data 屬性賦初值,而 @PostConstruct 注解的 init 方法會在 Spring 容器實例化完 InitService 后被執(zhí)行,將 “D” 添加到 data 列表中。所以當我們調用 getData() 方法時,返回的列表應該是 [A, B, C, D]。
接下來看看 @Autowired 和@PostConstruct 的具體執(zhí)行順序
@Service
public class TestA {
static {
System.out.println("staticA");
}
@Autowired
private TestB testB;
public TestA() {
System.out.println("這是TestA 的構造方法");
}
@PostConstruct
private void init() {
System.out.println("這是TestA的 init 方法");
testB.test();
}
}
@Service
public class TestB {
static {
System.out.println("staticB");
}
@PostConstruct
private void init() {
System.out.println("這是TestB的init 方法");
}
public TestB() {
System.out.println("這是TestB的構造方法");
}
void test() {
System.out.println("這是TestB的test方法");
}
}
構造方法:在對象初始化時執(zhí)行。執(zhí)行順序在static靜態(tài)代碼塊之后。
服務啟動后,輸出結果如下:
staticA
這是TestA 的構造方法
staticB
這是TestB的構造方法
這是TestB的init 方法
這是TestA的 init 方法
這是TestB的test方法
結論為:等@Autowired注入后,在執(zhí)行@PostConstruct注解的方法。
方式四:靜態(tài)代碼塊
static靜態(tài)代碼塊,在類加載的時候即自動執(zhí)行。
使用的static靜態(tài)代碼塊,實現(xiàn)原理為@Component + static代碼塊, spring boot項目在啟動過程中,會掃描@Component 并初始化相應的類,類的初始化過程會運行靜態(tài)代碼塊。
@Component
public class WordInitConfig {
static {
WordSegmenter.segWithStopWords("初始化分詞");
}
}
所以得到結論
static>constructer>@Autowired>@PostConstruct>ApplicationRunner>CommandLineRunner
到此這篇關于SpringBoot啟動時執(zhí)行初始化操作的幾種方式的文章就介紹到這了,更多相關SpringBoot執(zhí)行初始化操作內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
解決IDEA修改 .vmoptions 文件后導致無法啟動的問題
這篇文章主要介紹了解決IDEA修改 .vmoptions 文件后導致無法啟動的問題,需要的朋友可以參考下2020-12-12
SpringBoot配置文件properties和yml的實現(xiàn)
本文主要介紹了SpringBoot配置文件properties和yml的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-04-04
Java借助Spire.PDF?for?Java高效實現(xiàn)PDF自動排版
在?Java?開發(fā)中,處理?PDF?文檔的生成與編輯是常見的需求,本文將深入探討如何利用?Java?高效準確地設置?PDF?中的文字對齊方式,感興趣的小伙伴可以了解下2026-01-01
SpringBoot+Caffeine+Redis實現(xiàn)多級緩存的方法
多級緩存是指在系統(tǒng)中部署多層功能互補的緩存組件,讓請求按照預設順序依次訪問各層緩存,僅當所有緩存層均未命中時,才訪問底層數(shù)據庫的架構模式,這篇文章主要介紹了SpringBoot+Caffeine+Redis實現(xiàn)多級緩存的方法,需要的朋友可以參考下2026-02-02
MyBatis-Plus高效開發(fā)實戰(zhàn)指南
MyBatis-Plus(簡稱?MP)是?個MyBatis的增強工具,在MyBatis的基礎上只做增強不做改變,為簡化開發(fā),本文介紹MyBatis-Plus高效開發(fā)全攻略,感興趣的朋友跟隨小編一起看看吧2026-03-03

