1. 引言
在前两篇文章中,我们介绍了SpringBoot的启动流程,并深入分析了启动流程中的核心方法。本篇文章将进一步探讨SpringApplication类及其子组件,分析它们在启动过程中所扮演的角色和实现细节。
2. SpringApplication 子组件解析
2.1ApplicationContextInitializer 接口
ApplicationContextInitializer是一个接口,用于在Spring应用上下文刷新之前对其进行进一步的配置。
2.1.1 定义
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
void initialize(C applicationContext);
}
-
功能:initialize方法在应用上下文刷新之前被调用,用于对上下文进行自定义初始化。
2.1.2 使用
在SpringApplication的构造方法中,会加载所有 ApplicationContextInitializer 实现类:
public SpringApplication(Class<?>... primarySources) {
this.setInitializers((Collection) this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
}
2.2 ApplicationListener 接口
ApplicationListener是一个接口,用于监听Spring框架中的各种事件。
2.2.1 定义
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}
-
功能:onApplicationEvent方法在事件发布时被调用,用于处理相应的事件。
2.2.2 使用
在SpringApplication的构造方法中,会加载所有ApplicationListener实现类:
public SpringApplication(Class<?>... primarySources) {
this.setListeners((Collection) this.getSpringFactoriesInstances(ApplicationListener.class));
}
2.3 SpringApplicationRunListeners 类
SpringApplicationRunListeners类用于管理多个 SpringApplicationRunListener实例,并在不同的启动阶段调用它们。
2.3.1 定义
class SpringApplicationRunListeners {
private final List<SpringApplicationRunListener> listeners;
SpringApplicationRunListeners(Log logger, Collection<? extends SpringApplicationRunListener> listeners) {
this.listeners = new ArrayList<>(listeners);
}
void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
void environmentPrepared(ConfigurableEnvironment environment) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.environmentPrepared(environment);
}
}
void contextPrepared(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.contextPrepared(context);
}
}
void contextLoaded(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.contextLoaded(context);
}
}
void started(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.started(context);
}
}
void running(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.running(context);
}
}
void failed(ConfigurableApplicationContext context, Throwable exception) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.failed(context, exception);
}
}
}
-
功能:在应用程序启动的不同阶段,调用所有注册的 SpringApplicationRunListener 实例。
3. 关键子组件的具体实现
3.1 DefaultApplicationArguments 类
DefaultApplicationArguments类实现了ApplicationArguments接口,解析和封装传递给应用程序的命令行参数。
3.1.1 定义
public class DefaultApplicationArguments implements ApplicationArguments {
private final Source source;
public DefaultApplicationArguments(String[] args) {
this.source = new Source(args);
}
@Override
public String[] getSourceArgs() {
return this.source.getSourceArgs();
}
@Override
public Set<String> getOptionNames() {
return this.source.getOptionNames();
}
@Override
public boolean containsOption(String name) {
return this.source.containsOption(name);
}
@Override
public List<String> getOptionValues(String name) {
return this.source.getOptionValues(name);
}
@Override
public List<String> getNonOptionArgs() {
return this.source.getNonOptionArgs();
}
}
-
功能:解析和封装命令行参数,提供便捷的参数访问方法。
3.2 Banner 类
Banner接口用于在应用程序启动时显示横幅信息。
3.2.1 定义
@FunctionalInterface
public interface Banner {
void printBanner(Environment environment, Class<?> sourceClass, PrintStream out);
Banner DEFAULT = new SpringBootBanner();
}
-
功能:printBanner方法用于打印横幅信息,SpringBoot提供了默认实现 SpringBootBanner。
3.2.2 使用
在SpringApplication的run方法中,调用printBanner方法显示横幅信息:
Banner printedBanner = this.printBanner(environment);
4. 启动流程的细节分析(续)
4.1 prepareContext 方法
prepareContext 方法用于配置应用上下文。
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments,
Banner printedBanner) {
context.setEnvironment(environment);
this.postProcessApplicationContext(context);
this.applyInitializers(context);
listeners.contextPrepared(context);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
}
-
功能:设置环境,调用初始化器,注册横幅,通知监听器上下文已准备就绪。
4.2 applyInitializers 方法
applyInitializers方法用于调用所有ApplicationContextInitializer实例的 initialize方法。
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
initializer.initialize(context);
}
}
-
功能:遍历并调用所有 ApplicationContextInitializer 实例对上下文进行自定义初始化。
4.3 callRunners 方法
callRunners方法用于调用所有实现了CommandLineRunner和 ApplicationRunner接口的 Bean。
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
runners.addAll(context.getBeansOfType(ApplicationRunner.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);
}
}
}
-
功能:获取所有实现CommandLineRunner和ApplicationRunner接口的 Bean 并按顺序调用。
5. 结论
通过详细分析SpringApplication类及其子组件,我们进一步理解了 SpringBoot启动过程的内部机制。这些组件在启动过程中的各个阶段发挥了关键作用,确保了应用程序的顺利启动和运行。在后续的文章中,我们将继续探索SpringBoot的其他重要特性和实现细节。