Spring Boot之 CommandLineRunner、ApplicationRunner和@PostConstruct

在使用Spring Boot開發的工做中,咱們常常會須要遇到一種功能需求,好比在服務啓動時候,去加載一些配置,去請求一下其餘服務的接口。Spring Boot給咱們提供了三種經常使用的實現方法:
第一種是實現CommandLineRunner接口,
第二種是實現ApplicationRunner接口
第三種是使用註解:@PostConstruct

一、CommandLineRunner

一、CommandLineRunner執行的時間節點是在Application完成初始化工做以後。
二、CommandLineRunner在有多個實現的時候,可使用@order註解指定執行前後順序。
三、源碼在:org.springframework.boot.SpringApplication#run(),能夠看看

咱們先看一下CommandLineRunner的源碼:java

package org.springframework.boot;

@FunctionalInterface
public interface CommandLineRunner {
    void run(String... args) throws Exception;
}

SpringApplication源碼:git

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        ConfigurableApplicationContext context = null;
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting(bootstrapContext, this.mainApplicationClass);

        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }

callRunners方法源碼:spring

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);
            }

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

    }

咱們寫一個例子實現:bootstrap

import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
@Order(1)
public class CommandLineRunnerTest implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("----CommandLineRunnerTest1 start---"+ Arrays.toString(args));
    }
}

二、ApplicationRunner

ApplicationRunner跟CommandLineRunner是區別是在run方法裏接收的參數不一樣,CommandLineRuner接收的參數是String... args,而ApplicationRunner的run方法的參數是ApplicationArguments

看看ApplicationRunner的源碼:微信

package org.springframework.boot;

@FunctionalInterface
public interface ApplicationRunner {
    void run(ApplicationArguments args) throws Exception;
}

咱們寫一個例子實現:app

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Set;

@Component
@Order(1)
public class ApplicationRunnerTest implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("---ApplicationRunnerTest start----");

        List<String> nonOptionArgs = args.getNonOptionArgs();
        System.out.println("[非選項參數]>>> " + nonOptionArgs);
        Set<String> optionNames = args.getOptionNames();
        for(String optionName: optionNames) {
            System.out.println("[選項參數]>>> name:" + optionName
                    + ";value:" + args.getOptionValues(optionName));
        }
    }
}

三、@PostConstruct

@PostConstruct是在javaEE5的時候引入的,它並非Spring提供的,可是Spring有對@PostConstruct的實現。而且是在對象加載完以後執行。

先看註解源碼less

@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}

咱們寫一個例子實現:ide

import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
public class PostConstructTest {

    @PostConstruct
    public void start(){
        System.out.println("---PostConstruct start---");
    }


}

運行代碼輸出結果 :
this

五、源碼

https://gitee.com/Qinux/comma...spa

微信公衆號:一凡碼農
歡迎交流
相關文章
相關標籤/搜索