SpringBoot这2个接口非常实用

1. 简介

如果你需要在SpringApplication启动后运行一些特定的代码,可以实现ApplicationRunnerCommandLineRunner接口。这两个接口的工作方式相同,都提供了一个run方法,在SpringApplication.run(…)完成之前调用。

2. 二者区别

ApplicationRunner方法签名

void run(ApplicationArguments args) throws Exception ;

CommandLineRunner方法签名

void run(String... args) throws Exception ;

这两个类的方法名都是run,仅仅是他们的参数不同,接下来查看具体参数有何不同

首先,在启动程序时添加如下参数

--pack.title=xxxooo --pack.version=1.0.1

ApplicationRunner参数

public void run(ApplicationArguments args) throws Exception {
  System.out.printf("AR Args: %s%n", Arrays.toString(args.getSourceArgs())) ;
  System.out.printf("AR 参数名: %s%n", args.getOptionNames()) ;
}

输出结果

通过上面的输出对比,ApplicationRunner对参数的操作方法更加的完善不仅包括了完整原始的参数信息,还将提供了其它获取所有参数名及参数名对应的值(上面并未调用对应方法getOptionValues)信息。

3. 执行时机

当执行SpringApplication#run方法时,最终执行如下的核心方法

public class SpringApplication {
  public ConfigurableApplicationContext run(String... args) {
    // ...
    try {
      // 准备上下文
      prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
      // 初始化Spring容器
      refreshContext(context);
      afterRefresh(context, applicationArguments);
      // ...
      // 调用ApplicationRunner和CommandLineRunner
      callRunners(context, applicationArguments);
    }
    try {
      if (context.isRunning()) {
        listeners.ready(context, startup.ready());
      }
    }
    return context;
  }
}

 这2个Runner执行顺序如下

private void callRunner(Runner runner, ApplicationArguments args) {
  if (runner instanceof ApplicationRunner) {
    callRunner(ApplicationRunner.class, runner, (applicationRunner) -> applicationRunner.run(args));
  }
  if (runner instanceof CommandLineRunner) {
    callRunner(CommandLineRunner.class, runner,
        (commandLineRunner) -> commandLineRunner.run(args.getSourceArgs()));
  }
}

先执行ApplicationRunner。

4. 实战案例

案例1

应用启动后,执行定时任务

@Component
public class TaskSchedulerInitializer implements ApplicationRunner {

  private final TaskScheduler taskScheduler;
  public TaskSchedulerInitializer(TaskScheduler taskScheduler) {
    this.taskScheduler = taskScheduler;
  }
  @Override
  public void run(ApplicationArguments args) throws Exception {
    taskScheduler.schedule(this::task, new CronTrigger("0/5 * * * * ?")) ;
  }
  private void task() {
    System.out.println("执行任务...") ;
  }
}

注:默认你还需要配置TaskScheduler。

案例2

预热缓存,容器启动后加载缓存数据到内存

@Component
public class CacheDataWarmup implements ApplicationRunner {

  private final CacheManager cacheManager ;
  private final SysDictService dictService ;
  public CacheDataWarmup(CacheManager cacheManager, SysDictService dictService) {
    this.cacheManager = cacheManager ;
    this.dictService = dictService ;
  }
  @Override
  public void run(ApplicationArguments args) throws Exception {
    List<SysDict> dicts = this.dictService.queryAll() ;
    this.cacheManager.getCache("dicts").put("allparams", dicts) ;
  }
}

注:确保你的环境中引入了cache starter(你也可以不引入,自己实现)。

案例3

加载外部资源文件

@Component
public class LoadOuterResource implements ApplicationRunner {

  private final ConfigurableEnvironment environment ;
  public LoadOuterResource(ConfigurableEnvironment environment) {
    this.environment = environment ;
  }

  @Override
  public void run(ApplicationArguments args) throws Exception {
    YamlPropertySourceLoader sourceLoader = new YamlPropertySourceLoader() ;
    List<PropertySource<?>> list;
    try {
      list = sourceLoader.load("pack", new ClassPathResource("com/pack/binder/properties/pack.yml"));
      list.forEach(propertySource -> environment.getPropertySources().addLast(propertySource)) ;
    } catch (IOException e) {
      e.printStackTrace() ;
    }
  }
}

以上案例,都有其它的处理方式,这里只是给大家演示这里的Runner都能做些什么。

5. 控制顺序

如果你项目中有多个Runner实现,并且希望按照一定的顺序执行,那么你可以通过如下方式定义执行顺序

  • 实现org.springframework.core.Ordered接口

  • 使用@Order注解

如下示例:

@Component
@Order(2)
public class FirstRunner implements ApplicationRunner {
  // ...
}
@Component
@Order(1)
public class SecondRunner implements ApplicationRunner {
  // ...
}

上面执行分别:SecondRunner -> FirstRunner。

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

missterzy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值