项目启动时执行指定任务如何实现?

简介: 项目启动时执行指定任务如何实现?
正如题目标题所讲,一个项目启动时,我需要执行指定任务,如:初始化数据库数据,外部配置参数加载到缓存,等等。说到这不得不讲讲ApplicationRunner和CommandLineRunner,这两个又有什么区别呢?让我们看看源吧!

ApplicationRunner


/**
 * Interface used to indicate that a bean should <em>run</em> when it is contained within
 * a {@link SpringApplication}. Multiple {@link ApplicationRunner} beans can be defined
 * within the same application context and can be ordered using the {@link Ordered}
 * interface or {@link Order @Order} annotation.
 *
 * @author Phillip Webb
 * @since 1.3.0
 * @see CommandLineRunner
 */
@FunctionalInterface
public interface ApplicationRunner {

  /**
   * Callback used to run the bean.
   * @param args incoming application arguments
   * @throws Exception on error
   */
  void run(ApplicationArguments args) throws Exception;

}

CommandLineRunner


/**
 * Interface used to indicate that a bean should <em>run</em> when it is contained within
 * a {@link SpringApplication}. Multiple {@link CommandLineRunner} beans can be defined
 * within the same application context and can be ordered using the {@link Ordered}
 * interface or {@link Order @Order} annotation.
 * <p>
 * If you need access to {@link ApplicationArguments} instead of the raw String array
 * consider using {@link ApplicationRunner}.
 *
 * @author Dave Syer
 * @see ApplicationRunner
 */
@FunctionalInterface
public interface CommandLineRunner {

  /**
   * Callback used to run the bean.
   * @param args incoming main method arguments
   * @throws Exception on error
   */
  void run(String... args) throws Exception;

}

乍眼一看就名字不一样,再一看还有传入的参数不一样其他都一样,再看看他们在SpringApplication中的区别

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

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

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

这不是就是复制黏贴吗?源码就这?让我来我也行,哈哈

其实看到上面的注释也大概明白,可以实现多个,执行顺序可以实现Ordered接口或根据@Order注解来排序。

CommandLineRunner的使用示例


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

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

当然你也可以这样写


@Component
//@Order(1)
public class MyCommandLineRunner1 implements CommandLineRunner, Ordered {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("MyCommandLineRunner1------>" + Arrays.toString(args));
    }

    @Override
    public int getOrder() {
        return 1;
    }
}

@Component
//@Order(2)
public class MyCommandLineRunner2 implements CommandLineRunner, Ordered {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("MyCommandLineRunner2------>" + Arrays.toString(args));
    }

    @Override
    public int getOrder() {
        return 2;
    }
}

我们可以配置在系统启动时需要传入的参数,这里以 intelliJ IDEA 为例,单击右上角的编辑启动配置。

640.png

640.png

参数之间使用空格隔开。

项目启动后的运行结果
640.png

ApplicationRunner的使用示例


@Component
@Order(1)
public class MyApplicationRunner1 implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("MyApplicationRunner1------>" + Arrays.toString(args.getSourceArgs()));
    }
}

@Component
@Order(2)
public class MyApplicationRunner2 implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("MyApplicationRunner2------>" + Arrays.toString(args.getSourceArgs()));
    }
}

项目启动后的运行结果

640.png
你会发现很多人都会用ApplicationRunner,你自己去写,然后品,你细品,你就知道原因了。

相关文章
|
25天前
|
Java 调度
Java实现定时启动,且只执行一次,如何实现?
【10月更文挑战第18天】Java实现定时启动,且只执行一次,如何实现?
160 3
|
4月前
|
Java Serverless 应用服务中间件
函数计算操作报错合集之JVM启动时找不到指定的日志目录,该如何解决
Serverless 应用引擎(SAE)是阿里云提供的Serverless PaaS平台,支持Spring Cloud、Dubbo、HSF等主流微服务框架,简化应用的部署、运维和弹性伸缩。在使用SAE过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
|
5月前
|
消息中间件 XML Java
经验大分享:spring项目在启动的时候执行方法初始化
经验大分享:spring项目在启动的时候执行方法初始化
58 0
|
6月前
|
XML Java 开发者
springboot 启动原理、启动过程、启动机制的介绍
【5月更文挑战第13天】Spring Boot 是一种基于 Java 的框架,用于创建独立的、生产级别的 Spring 应用程序。它的主要目标是简化 Spring 应用的初始搭建和开发过程,同时提供一系列大型项目常见的非功能性特征(如嵌入式服务器、安全性、度量、健康检查和外部化配置)。
431 3
|
Java
自动执行任务:SpringBoot启动期间的最佳实践
自动执行任务:SpringBoot启动期间的最佳实践
65 0
|
6月前
|
Java
SpringBoot关闭过程中是如何销毁一个DisposableBean的?
SpringBoot关闭过程中是如何销毁一个DisposableBean的?
61 0
|
缓存 Java 数据中心
Hystrix执行时内部原理
Hystrix执行时内部原理
52 0
|
消息中间件 网络协议 关系型数据库
Java应用程序读取外部配置文件
当我们在服务器上安装一些软件服务时,如 MySQL、Kafka、ES 等,在启动服务的时候,脚本会读取默认路径下的配置文件,如果配置文件没有放到默认的路径下,我们也可以通过参数的方式指定,通过这个配置文件,可以灵活方便的开始某些功能或调整某些参数,不用重新对源码进行修改、编译和发布了。 所以,我们工作当中有时希望可以把配置文件放在程序外,这样就可以做到配置与业务分离,在项目中使用的 properties,这里就说一下如何用 properties 配置文件,默认加载 classpath 下的文件,如果通过参数指定了文件路径就可以使用外部配置了。
定义一个事件需要单独新建一个文件吗?底层原理是什么?
定义一个事件需要单独新建一个文件吗?底层原理是什么?
|
Java
SpringBoot项目启动过程中做数据资源初始化的方式
SpringBoot项目启动过程中做数据资源初始化的方式
500 0