首页 > 其他分享 >Spring Boot 中的 ApplicationRunner 和 CommandLineRunner

Spring Boot 中的 ApplicationRunner 和 CommandLineRunner

时间:2023-03-28 23:00:27浏览次数:41  
标签:CommandLineRunner run Spring args Boot public ApplicationRunner Order

前言

一般项目中的初始化操作,初次遇见,妙不可言。如果你还有哪些方式可用于初始化操作,欢迎在评论中分享出来~

ApplicationRunner 和 CommandLineRunner

Spring Boot 应用,在启动的时候,如果想做一些事情,比如预先加载并缓存某些数据,读取某些配置等等。总而言之,做一些初始化的操作时,那么 Spring Boot 就提供了两个接口帮助我们实现。

这两个接口是:

  • ApplicationRunner 接口
  • CommandLineRunner 接口

源码如下:

ApplicationRunner

package org.springframework.boot;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

/**
 * 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

package org.springframework.boot;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

/**
 * 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
 * @since 1.0.0
 * @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;

}

可以看到,这两个接口的注释几乎一模一样,如出一辙。大致的意思就是,这两个接口可以在 Spring 的环境下指定一个 Bean 运行(run)某些你想要做的事情,如果你有多个 Bean 进行指定,那么可以通过 Ordered 接口或者 @Order 注解指定执行顺序。

说白了,就是可以搞多个实现类实现这两个接口,通过 @Order 确定实现类的谁先运行,谁后运行

@Order

再看看 @Order 注解的源码:

/**
 * {@code @Order} defines the sort order for an annotated component.
 *
 * <p>The {@link #value} is optional and represents an order value as defined in the
 * {@link Ordered} interface. Lower values have higher priority. The default value is
 * {@code Ordered.LOWEST_PRECEDENCE}, indicating lowest priority (losing to any other
 * specified order value).
 * ..... 省略剩下的注释
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Documented
public @interface Order {

	/**
	 * The order value.
	 * <p>Default is {@link Ordered#LOWEST_PRECEDENCE}.
	 * @see Ordered#getOrder()
	 */
	int value() default Ordered.LOWEST_PRECEDENCE;

}

Ordered.LOWEST_PRECEDENCE 的默认值是 Integer.MAX_VALUE

在顶部的注释中,可以知道,@Order 注解是给使用了 @Component 注解的 Bean 定义排序顺序(defines the sort order for an annotated component),然后 @Order 注解的 value 属性值越低,那么代表这个 Bean 有着更高的优先级(Lower values have higher priority)。

测试

分别写两个实现类,实现这两个接口,然后启动 Spring Boot 项目,看看执行顺序

ApplicationRunnerImpl:

@Slf4j
@Component
public class ApplicationRunnerImpl implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("我正在加载 ------------------> ApplicationRunnerImpl");
    }
}

CommandLineRunnerImpl:

@Slf4j
@Component
public class CommandLineRunnerImpl implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        log.info("我正在加载 ------------------> CommandLineRunnerImpl");
    }
}

控制台输出:

2023-03-26 15:46:38.344  INFO 25616 --- [           main] c.g.demo.init.ApplicationRunnerImpl      : 我正在加载 ------------------> ApplicationRunnerImpl
2023-03-26 15:46:38.344  INFO 25616 --- [           main] c.g.demo.init.CommandLineRunnerImpl      : 我正在加载 ------------------> CommandLineRunnerImpl

可以看到,是 ApplicationRunnerImpl 先运行的,CommandLineRunnerImpl 后运行的。

我们给 CommandLineRunnerImpl 加上 @Order 注解,给其 value 属性设置 10:

@Slf4j
@Order(10)
@Component
public class CommandLineRunnerImpl implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        log.info("我正在加载 ------------------> CommandLineRunnerImpl");
    }
}

控制台输出:

2023-03-26 15:50:43.524  INFO 16160 --- [           main] c.g.demo.init.CommandLineRunnerImpl      : 我正在加载 ------------------> CommandLineRunnerImpl
2023-03-26 15:50:43.524  INFO 16160 --- [           main] c.g.demo.init.ApplicationRunnerImpl      : 我正在加载 ------------------> ApplicationRunnerImpl

区别

回到这两个接口,看似一模一样,但肯定有小小区别的,最主要的区别就是接口的抽象方法的参数

ApplicationRunner:

  • void run(ApplicationArguments args) throws Exception;

CommandLineRunner:

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

具体来说,ApplicationRunner 接口的 run 方法中的参数为 ApplicationArguments 对象,该对象封装了应用程序启动时传递的命令行参数和选项。

CommandLineRunner 接口的 run 方法中的参数为 String 数组,该数组直接包含了应用程序启动时传递的命令行参数和选项。

测试

打印下命令行参数:

@Slf4j
@Component
public class ApplicationRunnerImpl implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner: optionNames = " + args.getOptionNames() + ", sourceArgs = " + args.getSourceArgs());
    }
}
@Slf4j
@Component
public class CommandLineRunnerImpl implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("CommandLineRunner: " + Arrays.toString(args));
    }
}

用 Maven 打包项目为 Jar 包,启动该 Jar 包:

// 使用 java -jar 启动,加上两个参数:name 和 description
java -jar demo-0.0.1-SNAPSHOT.jar --name=god23bin --description=like_me

输出:

ApplicationRunner: optionNames = [name, description]sourceArgs = [Ljava.lang.String;@5c90e579
CommandLineRunner: [--name=god23bin, --description=like_me]

最后的最后

由本人水平所限,难免有错误以及不足之处, 屏幕前的靓仔靓女们 如有发现,恳请指出!

最后,谢谢你看到这里,谢谢你认真对待我的努力,希望这篇博客对你有所帮助!

你轻轻地点了个赞,那将在我的心里世界增添一颗明亮而耀眼的星!

标签:CommandLineRunner,run,Spring,args,Boot,public,ApplicationRunner,Order
From: https://www.cnblogs.com/god23bin/p/spring_boot_application_runner_and_command_line_runner.

相关文章

  • SpringBoot 集成支付宝的各种应用场景
    SpringBoot是一个非常流行的Java框架,它提供了一种快速、简便的方式来开发基于Java的Web应用程序。支付宝是中国最大的第三方支付平台,它提供了丰富的API,支持多种支付方式。......
  • 【SpringMVC-03】拦截器+类型转换器+数据校验以及异常映射,文件上传和下载
    第一章拦截器(重点)1.概念1.1使用场景1.1.1生活中坐地铁的场景为了提高乘车效率,在乘客进入站台前统一检票:1.1.2程序中的校验登录场景在程序中,使用拦截器在请求到达具体......
  • 【实战】SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
    JavaDogChatv1.0.0基于SpringBoot+uniapp简单通讯聊天软件......
  • 动力节点王鹤SpringBoot3学习笔记——JDK新特性
    一、JDK关注的新特性1.1搭建学习环境JDK:JDK19OpenJDK:https://jdk.java.net/19/LibericaJDK:https://bell-sw.com/pages/downloads/,是一个OpenJDK发行版,为云原生,......
  • Spring 事件
    事件Spring的默认事件是用来监听容器的,有如下事件:ContextStartedEvent、ContextStoppedEvent、ContextClosedEvent、ContextRefreshedEvent,分别表示容器启动、停止、关闭......
  • Ubuntu服务器下部署Springboot项目教程
    IDEA是Springboot服务器后台的开发工具,软件自备,项目自备。1.进入IDEA,点击IDEA最右边的Maven->Lifecycle->package2.打包之后,你可以在项目文件夹的target文件夹里面看到一个x......
  • 19-springboot自动配置原理
    SpringBoot自动配置原理(SpringBoot自动装配原理,SpringBootstarter原理)SpringBoot可以根据定义在classpath下的类,自动的给你生成一些Bean,并加载到Spring的Context中,自动配......
  • Spring Aop 常见注解和执行顺序
    SpringAop常见注解和执行顺序IOC、AOP、Bean注入、Bean的生命周期、Bean的循环依赖首先我们一起来回顾一下SpringAop中常用的几个注解:@Before 前置通知:目......
  • SpringBoot+RocketMq+Mybatis项目整合demo
    转载自:https://blog.csdn.net/mikewuhao/article/details/106666109 ============= Demo实现的功能项目启动生产者和消费者2个服务后,生产者端执行用户查询,从数据......
  • Spring boot 、Vue学习体会
    近期集中学习了Springboot、Vue等技术,学习过程也是不断碰壁,总的来说自认为有些涨进,抓住核心、深入关键、逐步剖析。两个技术分别负责后台和前端,学习后一个感受,两个技术......