SpringBoot2.x入门:使用CommandLineRunner钩子接口

简介: 这篇文章是《SpringBoot2.x入门》专辑的「第6篇」文章,使用的SpringBoot版本为2.3.1.RELEASE,JDK版本为1.8。这篇文章主要简单聊聊钩子接口CommandLineRunner和ApplicationRunner,下文有时候统称两者为Runner。

微信截图_20220513123019.png


前提



这篇文章是《SpringBoot2.x入门》专辑的第6篇文章,使用的SpringBoot版本为2.3.1.RELEASEJDK版本为1.8


这篇文章主要简单聊聊钩子接口CommandLineRunnerApplicationRunner,下文有时候统称两者为Runner


Runner的回调时机



参考org.springframework.boot.SpringApplication#run()方法的源码,可以知道CommandLineRunnerApplicationRunner的回调时机:


微信截图_20220513123028.png


在所有的CommandLineRunnerApplicationRunner回调之前,下面的步骤已经确保执行完毕:


  1. Environment内置变量的创建和属性填充已经完成。
  2. Banner已经打印完毕。
  3. ApplicationContextBeanFactory创建完成,并且完成了上下文刷新(refreshContext),意味着所有单例的Bean完成了初始化以及属性装配。
  4. Servlet容器启动成功,如内置的TomcatJetty容器已经正常启动,可以正常接收请求和处理。
  5. 启动信息完成打印,一般会看到日志输出类似Started OrderExportApplication in XXX seconds (JVM running for YYY)

也就是CommandLineRunner或者ApplicationRunner回调的时候,可以使用所有上下文中存在的单例BeanEnvironment内置变量中已经存在的属性值,所以很多时候demo项目都会在CommandLineRunner或者ApplicationRunner中进行操作。


Runner的简单使用



CommandLineRunnerApplicationRunner没有本质区别,唯一的区别在:CommandLineRunner#run()接收来自于main方法的参数,类型是字符串数组(不定字符串数组),而ApplicationRunner#run()接收ApplicationArguments类型的参数,对应的实现类是DefaultApplicationArguments


可以直接把注解@Component应用在CommandLineRunner或者ApplicationRunner的实现类上,相对于把对应的实现单例添加到Spring上下文中。例如:


@Slf4j
@Component
public class CustomCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        log.info("CustomCommandLineRunner runs...");
    }
}
复制代码


也可以通过@Bean注解,直接作用于CommandLineRunner的匿名类对应的方法上,例如:


@Slf4j
@Configuration
public class CommandLineRunners {
    @Bean
    public CommandLineRunner commandLineRunner(){
        return args -> log.info("CommandLineRunners commandLineRunner");
    }
}
复制代码


或者直接在启动类实现CommandLineRunner接口(这种方式不推荐使用):


@Slf4j
@SpringBootApplication
public class Ch5Application implements CommandLineRunner {
    public static void main(String[] args) {
        SpringApplication.run(Ch5Application.class, args);
    }
    @Override
    public void run(String... args) throws Exception {
        log.info("Ch5Application CommandLineRunner runs...");
    }
}
复制代码


此外,可以通过实现org.springframework.core.Ordered接口或者@Order注解定义Runner回调的顺序,指定的顺序数越小,优先级越高。


Runner的使用场景



这一小节是根据个人的编程习惯提出的建议。Runner钩子接口回调的时候如果抛出异常,会直接导致应用进程退出,所以如果在Runner回调方法中一定要注意异常的捕获和处理。基于这个特性,结合前面分析Runner接口的回调时机,它适用的主要场景有:


  • 打印日志用于标识服务启动成功或者标识某些属性加载成功。
  • 设置属性值或者启动组件,例如开启某些组件的开关、一些应用级别缓存的加载、启动定时任务等等。
  • 预加载数据(更常见于一些测试场景中,可以结合@Profile注解使用,指定特定的profile才生效)。
  • 需要使用main方法的入参。


下面使用CommandLineRunner启动所有Quartz中的Job(记得先引入依赖spring-boot-starter-quartz以及quartz),为了简单起见调度器使用内存态:


@Slf4j
@DisallowConcurrentExecution
public class SimpleJob extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        log.info("SimpleJob run...");
    }
}
@Component
public class QuartzCommandLineRunner implements CommandLineRunner {
    @Autowired
    private Scheduler scheduler;
    @Override
    public void run(String... args) throws Exception {
        JobDetail job = JobBuilder.newJob(SimpleJob.class).storeDurably().withIdentity(JobKey.jobKey("SimpleJob")).build();
        // 30秒执行一次
        Trigger trigger = TriggerBuilder.newTrigger()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(30))
                .forJob(job).build();
        scheduler.scheduleJob(job, trigger);
    }
}
复制代码


启动应用后,日志如下:


微信截图_20220513123038.png


小结



本文demo项目仓库:



(本文完 c-2-d e-a-20200712 封面图来自于《可塑性记忆》)

相关文章
|
8天前
|
Java API 微服务
【Spring Boot系列】通过OpenAPI规范构建微服务服务接口
【4月更文挑战第5天】通过OpenAPI接口构建Spring Boot服务RestAPI接口
|
25天前
|
NoSQL Java Redis
SpringBoot集成Redis解决表单重复提交接口幂等(亲测可用)
SpringBoot集成Redis解决表单重复提交接口幂等(亲测可用)
292 0
|
26天前
|
Java API Spring
SpringBoot项目调用HTTP接口5种方式你了解多少?
SpringBoot项目调用HTTP接口5种方式你了解多少?
80 2
|
2月前
|
JSON 前端开发 Java
SpringBoot 的优雅的接口参数验证
1. 为什么需要参数验证 在应用程序的开发中,我们经常会遇到需要保证传入参数的正确性的情况。例如,当我们在注册用户时,需要验证用户填写的表单数据是否符合规范,是否缺少必填字段,或者格式是否正确,等等。如果不对参数进行验证,我们的应用程序可能会因此受到攻击或者运行出错。 为了保证参数的正确性,我们需要使用参数验证机制,来检测并处理传入的参数格式是否符合规范。 2. 如何进行参数验证 Spring Boot内置了一个很强大的参数验证框架——JSR 303 Bean Validation 标准,它可以对我们的实体类参数进行校验,并且可以给我们提供详细的错误提示信息。
50 1
|
3月前
|
缓存 Java 数据库
SpringBoot 接口:响应时间优化9个技巧!
今天聊聊 SpringBoot接口:响应时间优化的9个技巧。在实际开发中,提升接口响应速度是一件挺重要的事,特别是在面临大量用户请求的时候。好了,咱们直接切入正题。
249 0
|
2月前
|
算法 NoSQL Java
springboot整合redis及lua脚本实现接口限流
springboot整合redis及lua脚本实现接口限流
76 0
|
3天前
|
Java Maven Kotlin
[AIGC] 请你写一遍博客介绍 “使用idea+kotinlin+springboot+maven 结合开发一个简单的接口“,输出markdown格式,用中文回答,请尽可能详细
[AIGC] 请你写一遍博客介绍 “使用idea+kotinlin+springboot+maven 结合开发一个简单的接口“,输出markdown格式,用中文回答,请尽可能详细
|
26天前
|
Java Spring
SpringBoot+async异步调用接口以及几个任务同时完成和异步接口实现和调用
SpringBoot+async异步调用接口以及几个任务同时完成和异步接口实现和调用
24 0
|
1月前
|
Java API Maven
SpringBoot 调用外部接口的三种方式--学习总结
SpringBoot 调用外部接口的三种方式--学习总结
39 1