美文网首页
springboot 启动后立即执行自定义代码 (Command

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

作者: 黑铁大魔王 | 来源:发表于2020-08-19 17:33 被阅读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,很简单吧。

    相关文章

      网友评论

          本文标题:springboot 启动后立即执行自定义代码 (Command

          本文链接:https://www.haomeiwen.com/subject/xkvkjktx.html