1. 程式人生 > >Spring Boot 之 CommandLineRunner,ApplicationRunner

Spring Boot 之 CommandLineRunner,ApplicationRunner

我們在開發過程中會有這樣的場景:需要在容器啟動的時候執行一些內容,比如:讀取配置檔案資訊,資料庫連線,刪除臨時檔案,清除快取資訊,在Spring框架下是通過ApplicationListener監聽器來實現的。在Spring Boot中給我們提供了兩個介面來幫助我們實現這樣的需求。這兩個介面就是我們今天要講的CommandLineRunner和ApplicationRunner,他們的執行時機為容器啟動完成的時候。使用起來非常簡單。只需要實現CommandLineRunner或者ApplicationRunner介面

for example:

package com.batch.demo.service;

import
org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; /** * Created by WuTing on 2018/2/13. */
@Component public class CommandExecute implements CommandLineRunner { private Logger LOG = LoggerFactory.getLogger(CommandExecute.class); @Autowired private ApplicationContext context; @Override public void run(String... strings) throws Exception { LOG.debug("CommandExecute run"
); } }

當專案啟動成功後,就會執行run方法。那如果存在多個Runner又是如何執行的呢?
我們可以通過@Order或者實現Ordered來設定執行順序。執行順序是從小到大。

那到底runner是如何會在專案啟動後執行的呢?我們可以通過程式入口跟蹤程式碼找到。
1、找到程式入口,SpringApplication.run()
2、跟蹤run方法直至找到SpringApplication的public ConfigurableApplicationContext run(String… args)方法,在該方法中我們可以看到呼叫了afterRefresh方法,afterRefresh方法就是對runner的呼叫。

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        FailureAnalyzers analyzers = null;
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            new FailureAnalyzers(context);
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments); //呼叫runner
            listeners.finished(context, (Throwable)null);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9);
            throw new IllegalStateException(var9);
        }
    }
 protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
        this.callRunners(context, args);
    }

    private void callRunners(ApplicationContext context, ApplicationArguments args) {
        List<Object> runners = new ArrayList();
        runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
        runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
        AnnotationAwareOrderComparator.sort(runners);
        Iterator var4 = (new LinkedHashSet(runners)).iterator();

        while(var4.hasNext()) {
            Object runner = var4.next();
            if (runner instanceof ApplicationRunner) {
                this.callRunner((ApplicationRunner)runner, args);  //呼叫runner
            }

            if (runner instanceof CommandLineRunner) {
                this.callRunner((CommandLineRunner)runner, args);  //呼叫runner
            }
        }

    }

    private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
        try {
            runner.run(args);
        } catch (Exception var4) {
            throw new IllegalStateException("Failed to execute ApplicationRunner", var4);
        }
    }

    private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
        try {
            runner.run(args.getSourceArgs());
        } catch (Exception var4) {
            throw new IllegalStateException("Failed to execute CommandLineRunner", var4);
        }
    }

從原始碼可以看出, 會預設呼叫ApplicationRunner和CommandLineRunner型別的run方法。