微信公众号
SpringBoot源码系列文章
SpringBoot源码解析(一):SpringApplication构造方法
SpringBoot源码解析(二):引导上下文DefaultBootstrapContext
class="toc">
微信公众号
SpringBoot源码系列文章
SpringBoot源码解析(一):SpringApplication构造方法
SpringBoot源码解析(二):引导上下文DefaultBootstrapContext
前文深入解析了引导上下文DefaultBootstrapContext作为组件存储容器的角色,接下来将进入启动开始阶段的内容。
SpringBoot版本2.7.18SpringApplication的run方法的执行逻辑如下,本文将详细介绍第2小节:获取启动监听器,调用启动开始方法
// SpringApplication类方法
public ConfigurableApplicationContext run(String... args) {
// 记录应用启动的开始时间
long startTime = System.nanoTime();
// 1.创建引导上下文,用于管理应用启动时的依赖和资源
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 配置无头模式属性,以支持在无图形环境下运行
// 将系统属性 java.awt.headless 设置为 true
configureHeadlessProperty();
// 2.获取Spring应用启动监听器,用于在应用启动的各个阶段执行自定义逻辑
SpringApplicationRunListeners listeners = getRunListeners(args);
// 启动开始方法(发布开始事件、通知应用监听器ApplicationListener)
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 4.解析应用参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 5.准备应用环境,包括读取配置文件和设置环境变量
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 配置是否忽略 BeanInfo,以加快启动速度
configureIgnoreBeanInfo(environment);
// 6.打印启动Banner
Banner printedBanner = printBanner(environment);
// 7.创建应用程序上下文
context = createApplicationContext();
// 设置应用启动的上下文,用于监控和管理启动过程
context.setApplicationStartup(this.applicationStartup);
// 8.准备应用上下文,包括加载配置、添加 Bean 等
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 9.刷新上下文,完成 Bean 的加载和依赖注入
refreshContext(context);
// 10.刷新后的一些操作,如事件发布等
afterRefresh(context, applicationArguments);
// 计算启动应用程序的时间,并记录日志
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
// 11.通知监听器应用启动完成
listeners.started(context, timeTakenToStartup);
// 12.调用应用程序中的 `CommandLineRunner` 或 `ApplicationRunner`,以便执行自定义的启动逻辑
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
// 13.处理启动过程中发生的异常,并通知监听器
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
// 14.计算应用启动完成至准备就绪的时间,并通知监听器
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}
catch (Throwable ex) {
// 处理准备就绪过程中发生的异常
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
// 返回已启动并准备就绪的应用上下文
return context;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">// 2.获取Spring应用启动监听器,用于在应用启动的各个阶段执行自定义逻辑
SpringApplicationRunListeners listeners = getRunListeners(args);
// 启动方法(发布开始事件、通知应用监听器ApplicationListener)
listeners.starting(bootstrapContext, this.mainApplicationClass);
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">spring.factories文件获取SpringApplicationRunListener实现类(SpringBoot源码解析(一):启动流程之SpringApplication构造方法有详细介绍)
上下文初始化ApplicationContextInitializer、应用监听器ApplicationListener都通过调用无参构造函数来创建类的实例应用启动监听器SpringApplicationRunListener通过SpringApplication.class, String[].class这两参数的构造来创建实例ApplicationStartup作用提供启动性能的监控和分析工具,只有导入固定依赖才会生效,暂不研究SpringApplicationRunListener实现类的starting方法// SpringApplication类方法
private SpringApplicationRunListeners getRunListeners(String[] args) {
// 这两个参数就是获取SpringApplicationRunListener实现类构造函数的参数
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
this.applicationStartup);
}
// SpringApplicationRunListeners类属性
class SpringApplicationRunListeners {
private final Log log;
// 存储所有SpringApplicationRunListener应用启动监听器的集合
private final List<SpringApplicationRunListener> listeners;
private final ApplicationStartup applicationStartup;
...
// 启动方法
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
doWithListeners("spring.boot.application.starting",
// 遍历每个监听器并执行starting方法
(listener) -> listener.starting(bootstrapContext),
// 为启动步骤打标签,包含mainApplicationClass信息(若不为空)
(step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
});
}
...
// 使用给定的监听器操作和步骤操作,遍历所有监听器并执行相应操作
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
Consumer<StartupStep> stepAction) {
// 启动一个新的启动步骤,用于性能分析
StartupStep step = this.applicationStartup.start(stepName);
// 对每个监听器执行指定的动作
this.listeners.forEach(listenerAction);
// 如果存在步骤操作,则执行该操作
if (stepAction != null) {
stepAction.accept(step);
}
// 结束启动步骤
step.end();
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">EventPublishingRunListener这一个应用启动监听器![]()
SpringApplicationRunListener是SpringBoot框架中的一个接口,用于监听Spring应用程序启动过程的生命周期事件。通过实现该接口,可以在应用启动的各个阶段执行自定义逻辑。
public interface SpringApplicationRunListener {
/**
* 在应用程序启动开始时调用
* @param bootstrapContext 提供引导上下文,可在应用程序启动期间存储和共享数据。
*/
default void starting(ConfigurableBootstrapContext bootstrapContext) {
}
/**
* 当环境准备好时调用,可以在此阶段访问和修改应用程序环境。
* @param bootstrapContext 提供引导上下文。
* @param environment 配置的环境对象,可用于访问和自定义环境属性。
*/
default void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
ConfigurableEnvironment environment) {
}
/**
* 当 ApplicationContext 已创建但还未刷新时调用,可以对应用上下文进行进一步配置。
* @param context Spring 应用程序上下文,提供 Bean 工厂等信息。
*/
default void contextPrepared(ConfigurableApplicationContext context) {
}
/**
* 当 ApplicationContext 加载完成并已注册所有 Bean 后调用。
* 此时,Bean 已加载,但未初始化。
* @param context Spring 应用程序上下文。
*/
default void contextLoaded(ConfigurableApplicationContext context) {
}
/**
* 应用启动完成后调用,表示应用程序已启动并处于活动状态。
* @param context Spring 应用程序上下文。
* @param timeTaken 应用程序启动所花费的时间。
*/
default void started(ConfigurableApplicationContext context, Duration timeTaken) {
started(context);
}
/**
* 这是 `started` 的过时版本,仅为了兼容性保留。
* 应用启动完成后调用
* @param context Spring 应用程序上下文。
* @deprecated 使用 {@link #started(ConfigurableApplicationContext, Duration)} 替代
*/
@Deprecated
default void started(ConfigurableApplicationContext context) {
}
/**
* 当应用程序完全准备好可以接收请求时调用
* 此方法在 ApplicationRunner 和 CommandLineRunner 执行完毕后触发
* @param context Spring 应用程序上下文
* @param timeTaken 应用程序启动所花费的时间
*/
default void ready(ConfigurableApplicationContext context, Duration timeTaken) {
running(context);
}
/**
* 这是 `ready` 的过时版本,仅为了兼容性保留。
* 当应用程序完全启动时调用
* @param context Spring 应用程序上下文。
* @deprecated 使用 {@link #ready(ConfigurableApplicationContext, Duration)} 替代。
*/
@Deprecated
default void running(ConfigurableApplicationContext context) {
}
/**
* 在应用程序启动失败时调用,用于执行失败时的处理逻辑,比如记录错误日志或资源清理。
* @param context Spring 应用程序上下文。
* @param exception 导致启动失败的异常。
*/
default void failed(ConfigurableApplicationContext context, Throwable exception) {
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> 在SpringBoot应用启动过程的关键阶段触发,包括starting(启动开始)、environmentPrepared(环境准备完成)、contextPrepared(上下文准备完成)、contextLoaded(上下文加载完成)、started(启动完成)、ready(应用准备就绪)和 failed(启动失败),以便在每个阶段执行自定义逻辑。
下面是一个简单的 SpringApplicationRunListener 实现示例:
SpringBoot应用启动监听器需要SpringApplication和String[]参数,以便访问应用上下文和传递启动时的命令行参数,从而实现对启动事件的定制和响应。所以自定义的启动监听器也需要一个标准的构造函数,才能统一的创建SpringApplicationRunListener实例。
public class MyApplicationRunListener implements SpringApplicationRunListener {
public MyApplicationRunListener(SpringApplication application, String[] args) {
// 构造函数必须包含 SpringApplication 和 String[] 参数
}
@Override
public void starting() {
System.out.println("应用启动开始...");
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
System.out.println("环境已准备好...");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("ApplicationContext 已准备完成...");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("ApplicationContext 已加载...");
}
@Override
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
System.out.println("应用已启动...");
}
@Override
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
System.out.println("应用正在运行...");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("应用启动失败:" + exception.getMessage());
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">需要在META-INF/spring.factories文件中进行注册:
org.springframework.boot.SpringApplicationRunListener=com.example.MyApplicationRunListener
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">启动服务
![]()
可以看到除了异常启动失败的触发,一共有6个触发的地方。本文就只介绍启动开始阶段触发的操作。
在进入启动方法之前,需要先了解下事件和广播器。
SpringApplicationEvent是SpringBoot框架中的一个重要概念,属于事件发布/订阅机制的一部分。它允许应用程序在特定事件发生时发布事件,其他组件可以订阅这些事件并做出相应的处理。这种机制提高了系统的解耦性和可扩展性。
类图如下:
![]()
EventObject是Java标准库中的类,是所有事件的通用基类source属性表示事件的来源对象
// 所有事件状态对象的根类。所有的事件对象都应从此类派生
public class EventObject implements Serializable {
private static final long serialVersionUID = 5516075349620653480L;
// 事件最初发生的对象。使用 transient 修饰符表明该字段不会被序列化。
protected transient Object source;
// 构造一个原型事件
public EventObject(Object source) {
// 检查 source 是否为 null,避免不合法的事件源
if (source == null)
throw new IllegalArgumentException("null source");
// 设置事件的源对象
this.source = source;
}
// 获取事件最初发生的对象
public Object getSource() {
return source;
}
// 返回该EventObject的字符串表示形式(包括类的名称和事件源信息)
public String toString() {
return getClass().getName() + "[source=" + source + "]";
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">ApplicationEvent是所有Spring应用事件的基类,用于定义基础属性和行为timestamp表示事件发生的时间// 抽象类,应用事件的基类。所有应用事件都应扩展此类
public abstract class ApplicationEvent extends EventObject {
private static final long serialVersionUID = 7099057708183571937L;
// 事件发生的系统时间(时间戳)
private final long timestamp;
// 构造
public ApplicationEvent(Object source) {
// 调用父类 EventObject 的构造函数,传递事件源
super(source);
// 设置事件的时间戳,记录事件创建时的系统时间
this.timestamp = System.currentTimeMillis();
}
// 此构造函数通常用于测试场景
public ApplicationEvent(Object source, Clock clock) {
// 调用父类 EventObject 的构造函数,传递事件源
super(source);
// 设置时间戳为由指定 Clock 提供的时间
this.timestamp = clock.millis();
}
// 返回事件发生的时间
public final long getTimestamp() {
return this.timestamp;
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">命令行参数信息public abstract class SpringApplicationEvent extends ApplicationEvent {
// 启动应用时传递的命令行参数
private final String[] args;
// 构造一个新的 SpringApplicationEvent
public SpringApplicationEvent(SpringApplication application, String[] args) {
// 调用父类 ApplicationEvent 的构造方法,设置事件源为 SpringApplication 实例
super(application);
this.args = args;
}
// 获取触发此事件的 SpringApplication 实例
public SpringApplication getSpringApplication() {
// 将源对象强制转换为 SpringApplication 类型并返回
return (SpringApplication) getSource();
}
// 获取启动应用时传递的命令行参数
public final String[] getArgs() {
return this.args;
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">第一个事件,通常用于在应用启动时初始化资源或配置项Environment准备完成之后,ApplicationContext创建之前发布ApplicationContext初始化完成后发布ApplicationContext创建并加载完成后,但还未刷新前发布ApplicationContext已刷新之后发布应用启动并初始化完成,准备处理请求时发布启动失败时发布 ApplicationEventMulticaster的核心功能是管理监听器(ApplicationListener)的注册和注销,以及将事件广播给合适的监听器。
类图如下:默认唯一的抽象子类和实现类
![]()
ApplicationListener,并将事件发布给它们添加、移除和广播事件给注册的监听器的方法public interface ApplicationEventMulticaster {
// 添加一个监听器实例,以接收所有事件通知
void addApplicationListener(ApplicationListener<?> listener);
// 通过指定Bean名称添加一个监听器Bean,以接收所有事件通知
void addApplicationListenerBean(String listenerBeanName);
// 从通知列表中移除一个监听器
void removeApplicationListener(ApplicationListener<?> listener);
// 通过指定 Bean 名称,从通知列表中移除一个监听器 Bean
void removeApplicationListenerBean(String listenerBeanName);
// 从已注册的实例集合中移除所有匹配的监听器(predicate是一个条件过滤器)
void removeApplicationListeners(Predicate<ApplicationListener<?>> predicate);
// 从已注册的监听器Bean名称集合中移除所有匹配的监听器 Bean(predicate是一个条件过滤器)
void removeApplicationListenerBeans(Predicate<String> predicate);
// 移除此广播器注册的所有监听器
void removeAllListeners();
// 将给定的应用事件广播到合适的监听器
void multicastEvent(ApplicationEvent event);
// 将给定的应用事件广播到合适的监听器,eventType为事件的类型
void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">defaultRetriever:用于直接管理监听器列表,支持实时更新,保证监听器信息的准确性retrieverCache:提供缓存机制,通过事件类型和源类型匹配缓存的监听器列表,提高性能;每当监听器更新时被清空,以确保缓存数据的一致性public abstract class AbstractApplicationEventMulticaster
implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
// 默认监听器检索器
private final DefaultListenerRetriever defaultRetriever = new DefaultListenerRetriever();
// 用于缓存监听器检索的缓存Map
final Map<ListenerCacheKey, CachedListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);
...
// 添加监听器
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.defaultRetriever) {
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
// 添加监听器Bean
@Override
public void addApplicationListenerBean(String listenerBeanName) {
synchronized (this.defaultRetriever) {
this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
this.retrieverCache.clear();
}
}
// 省略类似添加和移除方法
...
// defaultRetriever持有所有注册的监听器集合
private class DefaultListenerRetriever {
// 应用程序监听器的集合,存储直接注册的监听器实例
public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
// 应用程序监听器的名称集合,存储监听器bean的名称,用于延迟加载
public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
...
}
// retrieverCache持有所有注册的监听器集合
private class CachedListenerRetriever {
// 应用程序监听器的集合
@Nullable
public volatile Set<ApplicationListener<?>> applicationListeners;
// 应用程序监听器的名称集合
@Nullable
public volatile Set<String> applicationListenerBeans;
...
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">监听器来决定是否忽略它们不感兴趣的事件同步执行,可以设置执行器使用线程池来处理public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
// 任务执行器,用于异步执行监听器,默认为空(同步执行)
@Nullable
private Executor taskExecutor;
// 错误处理器,用于处理监听器抛出的异常,默认为空
@Nullable
private ErrorHandler errorHandler;
// 懒加载的日志记录器,用于在需要时记录日志
@Nullable
private volatile Log lazyLogger;
// 创建一个新的 SimpleApplicationEventMulticaster 实例
public SimpleApplicationEventMulticaster() {
}
// 创建SimpleApplicationEventMulticaster时候
// 设置一个异步任务执行器,就可以实现多线程执行了
public void setTaskExecutor(@Nullable Executor taskExecutor) {
this.taskExecutor = taskExecutor;
}
...
// 将给定的应用事件广播到合适的监听器(核心方法)
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
// 获取符合条件的所有监听器并进行事件广播(包括匹配合适的监听器)
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
// 如果有任务执行器,则使用执行器异步执行监听器
executor.execute(() -> invokeListener(listener, event));
} else {
// 否则直接同步调用监听器
invokeListener(listener, event);
}
}
}
// 调用给定的监听器并传递给它给定的事件
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
} catch (Throwable err) {
// 使用错误处理器处理异常
errorHandler.handleError(err);
}
} else {
doInvokeListener(listener, event);
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 调用监听器的核心方法
listener.onApplicationEvent(event);
} catch (ClassCastException ex) {
...
}
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> 启动方法实际就是遍历调用应用启动监听器SpringApplicationRunListener实现类(只有一个EventPublishingRunListener)的starting方法。
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
// SpringApplication 对象,用于访问应用的配置信息和监听器
private final SpringApplication application;
// 启动参数
private final String[] args;
// 初始事件广播器,用于在启动阶段广播事件
private final SimpleApplicationEventMulticaster initialMulticaster;
/**
* 初始化一个事件广播器,并将所有应用监听器添加到广播器中。
*/
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
// 初始化一个事件广播器
this.initialMulticaster = new SimpleApplicationEventMulticaster();
// 将 SpringApplication 中的所有监听器添加到初始广播器中
for (ApplicationListener<?> listener : application.getListeners()) {
// 实际调用AbstractApplicationEventMulticaster的添加方法
this.initialMulticaster.addApplicationListener(listener);
}
}
// 返回该监听器的执行顺序。数字越小,优先级越高
@Override
public int getOrder() {
return 0; // 优先级最高
}
// 在应用启动初期调用
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
// 将应用开始事件广播到合适的监听器
this.initialMulticaster
.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
}
// 省略其他阶段的代码,后面走到对应流程在看具体操作
...
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">SimpleApplicationEventMulticaster的广播方法multicastEvent事件匹配监听器的方法在每个监听器中有定义![]()
// 一个处理应用事件的监听器接口。
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
// 响应应用事件的方法。当发布指定类型的事件时,该方法会被调用,
// 以便执行相应的业务逻辑。
void onApplicationEvent(E event);
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">getApplicationListeners,会遍历匹配每个监听器,直接定位核心方法事件类型和来源类型
smartListener.supportsEventType(eventType): 验证监听器是否支持指定的事件类型smartListener.supportsSourceType(sourceType): 验证监听器是否支持指定的事件来源类型// AbstractApplicationEventMulticaster类方法
protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
// 检查监听器是否为 GenericApplicationListener 类型
// 如果是,则直接使用;如果不是,则将其包装为 GenericApplicationListenerAdapter
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
// 检查监听器是否支持指定的事件类型和来源类型
// smartListener.supportsEventType(eventType): 验证监听器是否支持指定的事件类型
// smartListener.supportsSourceType(sourceType): 验证监听器是否支持指定的事件来源类型
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> 监听器分为两种形式,实现ApplicationListener<指定事件类型>或实现GenericApplicationListener(通过supportsEventType方法-支持事件类型和supportsSourceType方法-支持事件来源)。
![]()
如果监听器是普通方式实现ApplicationListener<指定事件类型>,那么会将监听器包装为GenericApplicationListenerAdapter,核心内容就是解析出指定事件类型的实际类型。
![]()
验证监听器是否支持指定的事件类型
GenericApplicationListenerAdapter实现了GenericApplicationListener的支持事件类型方法supportsEventTypeisAssignableFrom方表示当前类是否可以表示为指定类的超类或接口![]()
验证监听器是否支持指定的事件来源类型
![]()
如果监听器是实现GenericApplicationListener方法,那么匹配事件类型和来源都在监听器内部实现,如下以LoggingApplicationListener例如下:
![]()
![]()
LoggingApplicationListener用于初始化日志系统,根据application.properties或环境配置设置日志级别和格式(Spring Boot 的日志系统初始化通常是由该监听器负责)。具体内容后续文章单独讲。
至于BackgroundPreinitializer和DelegatingApplicationListener虽然匹配上了,但是这个启动开始阶段什么都没有做,后续其他阶段有操作时候再说。
应用启动监听器的获取和启动是运行过程中的第一个重要步骤SpringApplicationRunListener,该接口可以在应用启动的各个阶段执行自定义逻辑starting、environmentPrepared、contextPrepared等META-INF/spring.factories中进行注册以加入启动流程SpringApplicationEvent系列事件类型及其触发时机,分别对应应用的不同启动阶段ApplicationEventMulticaster广播器的结构和工作原理。它通过SimpleApplicationEventMulticaster将事件广播给符合条件的监听器,支持同步和异步广播EventPublishingRunListener来广播事件,其中SimpleApplicationEventMulticaster实现了事件的广播ApplicationListener<指定事件类型>或GenericApplicationListener来适配特定事件类型,监听器匹配时会检查事件类型和来源类型的支持性
评论记录:
回复评论: