共计 5065 个字符,预计需要花费 13 分钟才能阅读完成。
前言
个别我的项目中的初始化操作,首次遇见,妙不可言。如果你还有哪些形式可用于初始化操作,欢送在评论中分享进去~
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]
最初的最初
由自己程度所限,不免有谬误以及不足之处,屏幕前的靓仔靓女们
如有发现,恳请指出!
最初,谢谢你看到这里,谢谢你认真对待我的致力,心愿这篇博客对你有所帮忙!
你轻轻地点了个赞,那将在我的心里世界削减一颗亮堂而夺目的星!