计时器介绍
StopWatch 是 Spring 提供的秒表工具类,允许对多个任务进行计时,显示总运行时间和每个指定任务的运行时间,简单使用例子。
public class StopWatchTest {
@Test
public void testStopWatch() throws InterruptedException {
var stopWatch = new StopWatch("testWatch");
stopWatch.start("task1");
TimeUnit.SECONDS.sleep(2);
stopWatch.stop();
stopWatch.start("task2");
TimeUnit.SECONDS.sleep(1);
stopWatch.stop();
stopWatch.start("task3");
TimeUnit.SECONDS.sleep(3);
stopWatch.stop();
System.out.println(stopWatch.prettyPrint());
System.out.println(stopWatch);
}
}
启动加载器案例
实现 CommandLineRunner 和 ApplicationRunner 接口的类称为启动加载器,用于在 SpringApplication 启动完成后立即执行其 run 方法,多个启动加载器通过使用 Ordered 接口或 @Order 注释进行排序,Order 值相同时 ApplicationRunner 优先执行。
@Component
@Order(1)
public class FirstApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
System.out.println("\u001B[32m >>> startup first ApplicationRunner <<<");
}
}
@Component
@Order(1)
public class FirstCommandlineRunner implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("\u001B[32m >>> startup first CommandlineRunner <<<");
}
}
启动加载器原理解析
启动加载器调用的入口在 org.springframework.boot.SpringApplication#run(java.lang.String...)
方法的 callRunners 方法中。
public ConfigurableApplicationContext run(String... args) {
// 将启动参数包装为 ApplicationArguments
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// ...
listeners.started(context);
// SpringApplication 启动完成后执行
callRunners(context, applicationArguments);
// ...
listeners.running(context);
}
callRunners 的逻辑比较简单,从容器中获取所有实现 ApplicationRunner 和 CommandLineRunner 接口的实例,按 Order 排序后依次调用。
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
// 因为先加入 ApplicationRunner 后加入 CommandLineRunner,排序后 Order 值相同的 ApplicationRunner 靠前
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
ApplicationRunner 和 CommandLineRunner 唯一不同是 run 方法的入参不一样,ApplicationArguments 是对 String[] args
入参的包装,默认实现 DefaultApplicationArguments 会将 String[] args
解析成 CommandLineArgs。