CommandLineRunner的使用
- 接口定义
- 使用
- 执行顺序
- 使用 @Order 注解
- 实现Orderd接口
- 排序总结
接口定义
Spring官方给出的接口定义
package org.springframework.boot;
@FunctionalInterface
public interface CommandLineRunner {
void run(String... args) throws Exception;
}
在 Spring Boot 应用程序中,CommandLineRunner 是一个接口,用于定义在应用程序启动后执行的任务。它有一个单独的方法 run(),在应用程序启动完成后自动调用。
具体来说,CommandLineRunner 的 run() 方法会在 Spring Boot 应用程序完成启动过程后立即执行。这意味着在 Spring 上下文加载完毕、所有 Bean 实例化完成之后,run() 方法将被调用。
可以看到,该接口还是一个函数式接口,函数式的方式就不演示了,我们这里继承该接口实现方法即可
使用
在我们需要进行初始化的类中直接实现该接口的 run()
方法即可
注意:如果你要run方法能被执行,你必须将实现了该接口的类注入到Spring容器中
CommandLineRunner 接口通常用于在应用程序启动后执行一些初始化任务或准备工作,例如加载初始数据、设置定时任务、启动后台线程等。通过实现 CommandLineRunner 接口并覆盖 run() 方法,你可以将你的任务逻辑放在其中,以便在应用程序启动时自动执行。
@Component
public class MyComponent implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("MyComponent -> CommandLineRunner");
}
}
执行结果
可以看到该方法在Application started之后才执行
执行顺序
需要注意的是,如果应用程序中有多个实现了 CommandLineRunner 的类,它们的执行顺序可能是不确定的。如果你需要确保执行顺序,可以使用 @Order 注解或实现 org.springframework.core.Ordered 接口来指定顺序。
在 Spring Framework 中,@Order 注解用于指定组件的执行顺序。它可以应用于类级别或方法级别。
使用 @Order 注解
示例代码如下所示:
定义两个类,order分别为1和2
@Component
public class MyComponent1 implements CommandLineRunner {
Logger logger = LoggerFactory.getLogger(MyComponent1.class);
@Order(1)
@Override
public void run(String... args) throws Exception {
logger.info("MyComponent1 -> CommandLineRunner");
}
}
@Component
public class MyComponent2 implements CommandLineRunner {
Logger logger = LoggerFactory.getLogger(MyComponent2.class);
@Order(2)
@Override
public void run(String... args) throws Exception {
logger.info("MyComponent2 -> CommandLineRunner");
}
}
运行结果:
对于类级别的 @Order 注解,它指定了组件在 Spring 上下文中的加载顺序。具体来说,数值越小的组件将先被加载和初始化。如果没有显式指定 @Order 注解,默认情况下,组件的加载顺序是不确定的。
实现Orderd接口
实现org.springframework.core.Ordered 中的getOrder()方法
下面再创建两个类,并实现 org.springframework.core.Ordered 接口。
@Component
public class MyComponent3 implements Ordered, CommandLineRunner {
Logger logger = LoggerFactory.getLogger(MyComponent3.class);
@Override
public void run(String... args) throws Exception {
logger.info("MyComponent3 -> CommandLineRunner");
}
@Override
public int getOrder() {
return 3;
}
}
@Component
public class MyComponent4 implements Ordered, CommandLineRunner {
Logger logger = LoggerFactory.getLogger(MyComponent4.class);
@Override
public void run(String... args) throws Exception {
logger.info("MyComponent4 -> CommandLineRunner");
}
@Override
public int getOrder() {
return 4;
}
}
执行结果如下:
可以看到无论使用哪种方式都是order值更小的优先执行,但是实现org.springframework.core.Ordered接口的会比在方法上使用@Order注解的有更高的优先级,所有实现org.springframework.core.Ordered接口的类中的run方法会都会优先于在方法上使用@Order注解执行,无论设置的值是否比注解中的更小
我这里猜测可能是实现接口是类级别的order,所以会优先于方法级别的order,所以我又做了下面实验,将MyComponent1和MyComponent2中的@Order注解挪到类声明上,所以就变成了下面这样
@Order(1)
@Component
public class MyComponent1 implements CommandLineRunner {
Logger logger = LoggerFactory.getLogger(MyComponent1.class);
@Override
public void run(String... args) throws Exception {
logger.info("MyComponent1 -> CommandLineRunner");
}
}
@Order(2)
@Component
public class MyComponent2 implements CommandLineRunner {
Logger logger = LoggerFactory.getLogger(MyComponent2.class);
@Override
public void run(String... args) throws Exception {
logger.info("MyComponent2 -> CommandLineRunner");
}
}
再次执行结果:
果然MyComponent1和MyComponent2排到前面去了,看来猜测没有错
排序总结
- @Order注解在类上会比注解在方法上拥有更高的优先级
- 实现org.springframework.core.Ordered接口的getOrder()方法和@Order注解在类上是相同的优先级
- order值越小越先执行
- order值可以为负数,一样遵循越小越优先的规则