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方法。

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