springboot 启动后立即执行自定义代码 (Command

2020-08-19  本文已影响0人  黑铁大魔王

springboot项目启动之后,如何立即执行一段自定义的代码呢?
比如项目启动后,立即加载指定数据库表的数据进入缓存。

springboot提供了2个接口CommandLineRunner,ApplicationRunner。实现这2个接口的任意一个接口,都能够在springboot项目启动完成后,立即执行自定义代码。下面先上代码来简明扼要的展示一下。

/**
 * 第一种方式,实现CommandLineRunner
 */
@Component
public class RunnerAfterStartup implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("------++++++");
    }
}
/**
 * 第二种方式,实现ApplicationRunner
 */
@Component
public class RunnerAfterStartup2 implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("=======_______");
    }
}

上面两种方式任选一种,都可以实现在springboot项目启动之后,立即执行run方法里面的代码。区别在于,获取java -jar 后面参数的方式,这里不再深究。
好,达到目的的方式知道了,那接下来看看为何这样做就能达到目的吧。

又来到了大家喜闻乐见的源码环节了。
先来看个gif图


图01

如果要了解CommandLineRunner,ApplicationRunner,只要看上图里的这几步就可以了。
SpringApplication.run(App.class, args);开始,走完几个run方法之后,就来到下面

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
            configureIgnoreBeanInfo(environment);
            Banner printedBanner = printBanner(environment);
            context = createApplicationContext();
            exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            // ysm: 001
            refreshContext(context);
            afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
            }
            listeners.started(context);
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }

        try {
            listeners.running(context);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }

这个方法是springboot项目启动的主要方法,这里包括了环境配置,启动web服务等等,但是我们只需要看try语句块里的最后一行,callRunners(context, applicationArguments);
进入该方法里一看便知,代码如下:

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);
        for (Object runner : new LinkedHashSet<>(runners)) {
            if (runner instanceof ApplicationRunner) {
                callRunner((ApplicationRunner) runner, args);
            }
            if (runner instanceof CommandLineRunner) {
                callRunner((CommandLineRunner) runner, args);
            }
        }
    }

这段代码就是把实现了ApplicationRunner,CommandLineRunner接口的类加入runners,然后遍历runners,执行这些实现类里的run方法。

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

看下callRunner,很简单吧。

上一篇下一篇

猜你喜欢

热点阅读