springboot源碼解析-管中窺豹系列之Runner

一、前言

Springboot源碼解析是一件大工程,逐行逐句的去研究代碼,會很枯燥,也不容易堅持下去。

我們不追求大而全,而是試着每次去研究一個小知識點,最終聚沙成塔,這就是我們的springboot源碼管中窺豹系列。

二、Runner

假如我們想在springboot項目啓動完成之後,做點什麼,我們應該怎麼辦呢?

注意我們可以寫在bean的初始化方法裏面(我們後面講),但是我們要用到其它已經加載了的bean的能力,又怎麼辦呢?

當然加順序,加依賴也能解決,就是麻煩

這一節我們討論一下springboot項目的Runner,Runner是在spring加載完畢執行的,springboot有兩種Runner:

ApplicationRunner

CommandLineRunner

@FunctionalInterfacepublic interface ApplicationRunner {void run(ApplicationArguments args) throws Exception;}@FunctionalInterfacepublic interface CommandLineRunner {void run(String... args) throws Exception;}複製代碼

兩種除了參數不同,其它沒區別

ApplicationArguments是對傳參數組的封裝,本質也沒區別

只有執行順序上有區別,下面源碼會看到

三、用法

實現接口就可以了

import org.springframework.boot.ApplicationArguments;import org.springframework.boot.ApplicationRunner;import org.springframework.stereotype.Component;@Componentpublic class HelloRunner implements ApplicationRunner {        @Override    public void run(ApplicationArguments args) throws Exception {        System.out.println("hello runner");    }}複製代碼

因爲這時候spring已經加載完畢,你可以引入其它bean

啓動項目,你會發現在日誌最下方打印了上面的話

四、源碼解讀

我們直接找SpringApplication類的run方法,想看整體框架的去第一節。

public ConfigurableApplicationContext run(String... args) {    ...    try {                ...        callRunners(context, applicationArguments);                ...    }    catch (Throwable ex) {                ...    }    ...    return context;}複製代碼

我們直接定位到callRunners方法。

private void callRunners(ApplicationContext context, ApplicationArguments args) {    List runners = new ArrayList<>();    // (1) 找到ApplicationRunner的實現類,加到list裏面    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());    // (2) 找到CommandLineRunner的實現類,加到list裏面    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());    // (3) 排序    AnnotationAwareOrderComparator.sort(runners);    // (4) 鉤子回調    for (Object runner : new LinkedHashSet<>(runners)) {        if (runner instanceof ApplicationRunner) {            callRunner((ApplicationRunner) runner, args);        }        if (runner instanceof CommandLineRunner) {            callRunner((CommandLineRunner) runner, args);        }    }}複製代碼

總共分四步:

(1) 找到ApplicationRunner的實現類,加到list裏面

(2) 找到CommandLineRunner的實現類,加到list裏面

(3) 排序

(4) 鉤子回調

我們看一下canllRunner

private void callRunner(ApplicationRunner runner, ApplicationArguments args) {    try {        (runner).run(args);    }    catch (Exception ex) {        throw new IllegalStateException("Failed to execute ApplicationRunner", ex);    }}private void callRunner(CommandLineRunner runner, ApplicationArguments args) {    try {        (runner).run(args.getSourceArgs());    }    catch (Exception ex) {        throw new IllegalStateException("Failed to execute CommandLineRunner", ex);    }}複製代碼

除了傳參方式,都一樣。

上面說的執行順序問題,是先添加的ApplicationRunner,如果只有@Component,先執行ApplicationRunner

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章