搜索 K
Appearance
Appearance
Spring Boot 提供两个等价的「启动完成回调」接口,让业务能在「容器装配完成之后、SpringApplication.run() 返回之前」做一些初始化工作,比如建索引、预热缓存、扫描注解。
| 接口 | 入参 | 用途场景 |
|---|---|---|
ApplicationRunner | ApplicationArguments(自带 --key=value 解析) | 关心命令行参数时优先选这个 |
CommandLineRunner | String[] args(原始数组) | 只需要原始 main args 时使用 |
两者执行时机一致;如果同时存在多个,可通过 @Order 或实现 Ordered 控制顺序,数值小的先执行。
启动顺序
SpringApplication.run()
├─ refresh() ← 容器装配(Bean 创建、依赖注入)
├─ afterRefresh()
├─ callRunners() ← ApplicationRunner / CommandLineRunner 在这里执行
└─ 返回 ApplicationContext所以 Runner 里能拿到任何已注册的 Bean,但还没开始接收 HTTP 请求。
@Component
@RequiredArgsConstructor
public class DemoInitializer implements ApplicationRunner {
private final SomeBean bean; // 任意已注册 Bean 都可注入
@Override
public void run(ApplicationArguments args) {
// args.getOptionNames() → 启动参数 key 列表
// args.getOptionValues("env") → 对应 value 列表
bean.doInit();
}
}DdlInitializer 就是一个 ApplicationRunner,依赖三件事:
@Component
@RequiredArgsConstructor
public class DdlInitializer implements ApplicationRunner {
private final ClazzScanner scanner;
private final ModelRegistry registry;
private final BeanFactory beanFactory; // ← 用来取 AutoConfigurationPackages
@Override
public void run(ApplicationArguments args) {
String[] scanPackages = fetchScanPackages();
Set<Class<?>> classes = scanner.scan(scanPackages);
for (Class<?> clazz : classes) {
ModelDefinition definition = parseModel(clazz);
registry.register(definition);
}
}
}它没读 args,但选 ApplicationRunner 而非 CommandLineRunner,是为后续阶段(SQL 生成、DDL 执行)可能要根据 --ddl.mode=create-drop 这类命令行参数分流留个口子。
→ 详细见 《扫描机制 · 时序图》