在日常開發中,我們經常會遇到在項目啟動階段要做一些數據初始化等操作,并且隻在項目啟動時進行,後續不再執行。而在SpringBoot2.x中,可根據不同使用場景使用不同的方式去實現該功能。具體如下:
- 實現CommandLineRunner接口
- 實現ApplicationRunner接口
- 實現ApplicationListener接口
- 使用@PostConstruct 注解
- 實現InitializingBean接口
- CommandLineRunner、ApplicationRunner 接口是在容器啟動成功後的最後一步回調(類似開機自啟動)。區别在于接收的參數不一樣。CommandLineRunner 的參數是最原始的參數,沒有做任何處理。ApplicationRunner的參數是ApplicationArguments,是對原始參數做了進一步的封裝。
- 使用ApplicationListener,定義一個 ServletContextListener,然後監聽項目啟動和銷毀,在contextInitialized方式中編寫初始化業務邏輯即可。
- 使用 @PostConstruct 注解同樣可以幫助我們完成資源的初始化操作,前提是這些初始化操作不需要依賴于其它Spring beans的初始化工作。
啟動任務常用場景:
- 數據初始化
- 初始化系統參數
- 文件初始化
- 緩存初始化
- 定義 InitCommandLineRunner 并且實現 CommandLineRunner 接口
- 首先通過 @Component 注解将 InitCommandLineRunner 注冊為Spring容器中的一個 Bean。
- 添加 @Order 注解,表示這個啟動任務的執行優先級,因為在一個項目中,啟動任務可能有多個,所以需要有一個排序。@Order 注解中,數字越小,優先級越大,默認情況下,優先級的值為 Integer.MAX_VALUE,表示優先級最低。
- 在 run 方法中,編寫啟動任務的核心邏輯,當項目啟動時,run方法會被自動執行。run 方法的參數,來自于項目的啟動參數,即項目入口類中,main方法的參數會被傳到這裡
/**
* 功能描述: CommandLineRunner實現啟動任務
* @author TuYong
* @date 2022/6/14 14:16
*/
@Component
@Order(100)
@Slf4j
public class InitCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
log.info("讀取String數組參數初始化操作内容...");
}
}
測試結果如下:在 IDEA 中,可以通過如下方式來配置參數
啟動項目後,我們可以看到啟動過程中run方式被執行。
2.2 基于 ApplicationRunner 實現
代碼如下,自定義類InitApplicationRunner實現 ApplicationRunner 接口即可。用法同CommandLineRunner一緻,ApplicationRunner 可以接收更多類型的參數(ApplicationRunner 除了可以接收 CommandLineRunner 的參數之外,還可以接收 key/value 形式的參數)。具體獲取參數方法如下:
- args.getNonOptionArgs();用來獲取命令行中的無key參數(和CommandLineRunner一樣)。
- args.getOptionNames();用來獲取所有key/value形式的參數的key。
- args.getOptionValues(key));根據key獲取key/value 形式的參數的value。
- args.getSourceArgs(); 獲取命令行中的所有參數。
/**
* 功能描述: ApplicationRunner實現啟動任務
* @author TuYong
* @date 2022/6/14 14:31
*/
@Component
@Order(99)
@Slf4j
public class InitApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
//獲取命令行中的無key參數
List<String> nonOptionArgs = args.getNonOptionArgs();
log.info("InitApplicationRunner無key參數:{}",nonOptionArgs);
//獲取所有key/value形式的參數的key
Set<String> optionNames = args.getOptionNames();
for (String key : optionNames) {
//根據key獲取key/value 形式的參數的value
log.info("InitApplicationRunner有key參數:{}",args.getOptionValues(key));
}
//獲取命令行中的所有參數
String[] sourceArgs = args.getSourceArgs();
log.info("InitApplicationRunner所有參數:{}",Arrays.toString(sourceArgs));
}
}
測試結果如下:在 IDEA 中,可以通過如下方式來配置參數
啟動項目,可以看到控制台打印如下:
2.3 基于 ApplicationListener 實現
定義義一個 ServletContextListener,在contextInitialized方法中進行數據初始化操作即可。
@Component
@Slf4j
public class InitServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
//這裡編寫啟動任務代碼
log.info("監聽器初始化.....");
}
}
測試結果如下:
2.4 基于@PostConstruct注解實現
示例代碼如下,被@PostConstruct修飾的方法會在服務器加載Servlet的時候運行,并且隻會被服務器執行一次。創建bean的時候執行順序Constructor(構造方法) -> @Autowired(依賴注入) -> @PostConstruct(注釋的方法)
需要注意的是:
- 在spring創建bean的時候觸發,此時容器還未完全初始化完畢,如果邏輯中引用了還未完成初始化的bean會導緻異常 ,所以需要考慮加載順序
- 如果@PostConstruct方法内的邏輯處理時間較長,就會增加SpringBoot應用初始化Bean的時間,進而增加應用啟動的時間。因為隻有在Bean初始化完成後,SpringBoot應用才會打開端口提供服務,所以在此之前,應用不可訪問
/**
* 功能描述: 基于@PostConstruct實現啟動任務
* @author TuYong
* @date 2022/6/14 14:59
*/
@Service
@Slf4j
public class SysParamService {
@PostConstruct
public void initParam(){
//編寫業務邏輯代碼,比如從數據庫查詢系統參數放入緩存中
log.info("初始化系統參數......");
}
}
測試結果如下
2.5 基于 InitializingBean 實現
示例代碼如下:
/**
* 功能描述: 基于InitializingBean實現啟動任務
* @author TuYong
* @date 2022/6/14 15:25
*/
@Component
@Slf4j
public class MyInitializingBean implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
//編寫啟動任務代碼
log.info("InitializingBean 執行初始化任務...");
}
}
測試結果如下
,