javascript
javafx应用启动自动执行函数_一张图,理顺 Spring Boot应用在启动阶段执行代码的几种方式...
前言
有時候我們需要在應用啟動時執行一些代碼片段,這些片段可能是僅僅是為了記錄 log,也可能是在啟動時檢查與安裝證書 ,諸如上述業務要求我們可能會經常碰到
Spring Boot 提供了至少 5 種方式用于在應用啟動時執行代碼。我們應該如何選擇?本文將會逐步解釋與分析這幾種不同方式
CommandLineRunner
CommandLineRunner 是一個接口,通過實現它,我們可以在 Spring 應用成功啟動之后 執行一些代碼片段
@Slf4j@Component@Order(2)public class MyCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { log.info("MyCommandLineRunner order is 2"); if (args.length > 0){ for (int i = 0; i < args.length; i++) { log.info("MyCommandLineRunner current parameter is: {}", args[i]); } } }}當 Spring Boot 在應用上下文中找到 CommandLineRunner bean,它將會在應用成功啟動之后調用 run() 方法,并傳遞用于啟動應用程序的命令行參數
通過如下 maven 命令生成 jar 包:
mvn clean package通過終端命令啟動應用,并傳遞參數:
java -jar springboot-application-startup-0.0.1-SNAPSHOT.jar --foo=bar --name=rgyb查看運行結果:
到這里我們可以看出幾個問題:
??不要使用 @Order 太多
看到 order 這個 "黑科技" 我們會覺得它可以非常方便將啟動邏輯按照指定順序執行,但如果你這么寫,說明多個代碼片段是有相互依賴關系的,為了讓我們的代碼更好維護,我們應該減少這種依賴使用
小結
如果我們只是想簡單的獲取以空格分隔的命令行參數,那 MyCommandLineRunner 就足夠使用了
ApplicationRunner
上面提到,通過命令行啟動并傳遞參數,MyCommandLineRunner 不能解析參數,如果要解析參數,那我們就要用到 ApplicationRunner 參數了
@Component@Slf4j@Order(1)public class MyApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { log.info("MyApplicationRunner order is 1"); log.info("MyApplicationRunner Current parameter is {}:", args.getOptionValues("foo")); }}重新打 jar 包,運行如下命令:
java -jar springboot-application-startup-0.0.1-SNAPSHOT.jar --foo=bar,rgyb運行結果如下:
到這里我們可以看出:
小結
如果我們想獲取復雜的命令行參數時,我們可以使用 ApplicationRunner
ApplicationListener
如果我們不需要獲取命令行參數時,我們可以將啟動邏輯綁定到 Spring 的 ApplicationReadyEvent 上
@Slf4j@Component@Order(0)public class MyApplicationListener implements ApplicationListener { @Override public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { log.info("MyApplicationListener is started up"); }}運行程序查看結果:
到這我們可以看出:
小結
如果我們不需要獲取命令行參數,我們可以通過 ApplicationListener 創建一些全局的啟動邏輯,我們還可以通過它獲取 Spring Boot 支持的 configuration properties 環境變量參數
如果你看過我之前寫的 Spring Bean 生命周期三部曲:
- Spring Bean 生命周期之緣起
- Spring Bean 生命周期之緣盡
- Spring Aware 到底是什么?
那么你會對下面兩種方式非常熟悉了
@PostConstruct
創建啟動邏輯的另一種簡單解決方案是提供一種在 bean 創建期間由 Spring 調用的初始化方法。我們要做的就只是將 @PostConstruct 注解添加到方法中:
@Component@Slf4j@DependsOn("myApplicationListener")public class MyPostConstructBean { @PostConstruct public void testPostConstruct(){ log.info("MyPostConstructBean"); }}查看運行結果:
從上面運行結果可以看出:
小結
@PostConstruct 方法固有地綁定到現有的 Spring bean,因此應僅將其用于此單個 bean 的初始化邏輯;
InitializingBean
與 @PostConstruct 解決方案非常相似,我們可以實現 InitializingBean 接口,并讓 Spring 調用某個初始化方法:
@Component@Slf4jpublic class MyInitializingBean implements InitializingBean { @Override public void afterPropertiesSet() throws Exception { log.info("MyInitializingBean.afterPropertiesSet()"); }}查看運行結果:
從上面的運行結果中,我們得到了和 @PostConstruct 一樣的效果,但二者還是有差別的
?? @PostConstruct 和 afterPropertiesSet 區別afterPropertiesSet,顧名思義「在屬性設置之后」,調用該方法時,該 bean 的所有屬性已經被 Spring 填充。如果我們在某些屬性上使用 @Autowired(常規操作應該使用構造函數注入),那么 Spring 將在調用afterPropertiesSet 之前將 bean 注入這些屬性。但 @PostConstruct 并沒有這些屬性填充限制所以 InitializingBean.afterPropertiesSet 解決方案比使用 @PostConstruct 更安全,因為如果我們依賴尚未自動注入的 @Autowired 字段,則 @PostConstruct 方法可能會遇到 NullPointerExceptions
小結
如果我們使用構造函數注入,則這兩種解決方案都是等效的
源碼分析
請打開你的 IDE (重點代碼已標記注釋):
MyCommandLineRunner 和 ApplicationRunner 是在何時被調用的呢?
打開 SpringApplication.java 類,里面有 callRunners 方法
private void callRunners(ApplicationContext context, ApplicationArguments args) { List runners = new ArrayList<>(); //從上下文獲取 ApplicationRunner 類型的 bean runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); //從上下文獲取 CommandLineRunner 類型的 bean runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); //對二者進行排序,這也就是為什么二者的 order 是可以共享的了 AnnotationAwareOrderComparator.sort(runners); //遍歷對其進行調用 for (Object runner : new LinkedHashSet<>(runners)) { if (runner instanceof ApplicationRunner) { callRunner((ApplicationRunner) runner, args); } if (runner instanceof CommandLineRunner) { callRunner((CommandLineRunner) runner, args); } }}強烈建議完整看一下 SpringApplication.java 的全部代碼,Spring Boot 啟動過程及原理都可以從這個類中找到一些答案
總結
最后畫一張圖用來總結這幾種方式(高清大圖請查看原文:https://dayarch.top/p/spring-...)
靈魂追問
在寫 Spring Bean 生命周期時就有朋友問我與之相關的問題,顯然他們在概念上有一些含混,所以,仔細理解上面的問題將會幫助你加深對 Spring Bean 生命周期的理解。
作者:日拱一兵
轉載自:https://segmentfault.com/a/1190000021437254
總結
以上是生活随笔為你收集整理的javafx应用启动自动执行函数_一张图,理顺 Spring Boot应用在启动阶段执行代码的几种方式...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 调整分区个数_在重装系统的过程中,硬盘如
- 下一篇: kettle优化抽取数据速度_数据异构工