SpringBoot运行流程源码分析:run方法流程及监听器( 三 )


默认情况下 , Spring Boot在初始化过程中触发的事件也是交由EventPublishingRunListener来代理实现的 。 EventPublishingRunListener 的构造方法如下 。
public EventPublishingRunListener(SpringApplication application, Stringargs) {this.application = application;this.args = args;//创建 SimpleAppl icat ionEventMulticaster/播器this . initialMulticaster = new SimpleApplicationEventMulticaster();//遍历 Appl icat ionL istener 并关联 S impleAppl icat ionEventMulticasterfor (ApplicationListener listener : application. getListeners()) {this. initialMulticaster . addApplicationListener(listener);}通过源代码可以看出 , 该类的构造方法符合 SpringApplicationRunListener 所需的构造方法参数要求 , 该方法依次传递了 SpringApplication 和 String[ ]类型 。 在构造方法中初始化了该类的 3 个成员变量 。
-application :类 型为 SpringApplication, 是当前运行的 SpringApplication 实例 。
-args:启动程序时的命令参数 。
-initialMulticaster:类 型为 SimpleApplicationEventMulticaster,事件广播器 。
Spring Boot 完成基本的初始化之后 , 会遍历 SpringApplication 的所有 ApplicationListener实 例,并 将 它 们 与 SimpleApplicationEventMulticaster 进 行 关 联,方 便SimpleApplicationEvent-Multicaster 后续将事件传递给所有的监听器 。
EventPublishingRunListener 针对不同的事件提供了不同的处理方法 , 但它们的处理流程基本相同 。
SpringBoot运行流程源码分析:run方法流程及监听器文章插图
下面我们根据图 4-3 所示的流程图梳理一下 整个事件的流程 。
.程序启动到某个步骤后 , 调用 EventPublishingRunListener 的某个方法 。
EventPublishingRunListener 的具体方法将 application 参数和 args 参数封装到对应的事件中 。 这里的事件均为 SpringApplicationEvent 的实现类 。
.通过成员变量 initialMulticaster 的 multicastEvent 方法对事件进行广播 , 或通过该方法的ConfigurableApplicationContext 参数的 publishEvent 方法来对事件进行发布 。
.对应的 ApplicationListener 被触发 , 执行相应的业务逻辑 。
下面是 starting 方法的源代码 , 可对照上述流程进行理解 。 该方法其他功能类似 , 代码不再展示 。
public void starting() {this. initialMulticaster . multicastEvent(new ApplicationStartingEvent (this. application, this.args));}在上述源代码中你是否发现-个问题 , 某些方法是通过 initialMulticaster 的 multicastEvent进行事件的广播 , 某些方法是通过 context 参数的 publishEvent 方法来进行发布的 。 这是为什么呢?在解决这个疑问之前 , 我们先看一个比较特殊的方法 contextL oaded 的源代码 。
public void contextLoaded( ConfigurableApplicationContext context) {//遍历 application 中的所有监听器实现类for (ApplicationL istener listener : this . application. getL isteners()) {//如果为 Appl icationContextAware,则将上:下文信息设置到该监听器内if (listener instanceof Applicat ionContextAware) {((ApplicationContextAware) listener). setApplicationContext( context);//将 application 中的监听器实现类全部添加到上下文中context . addApplicationL istener(listener);// / "播事件 Appl icationPreparedEventthis. initialMulticaster . multicastEvent (new ApplicationPreparedEvent(this.application, this.args, context));}contextLoaded 方法在发布事件之前做了两件事:第一 , 遍历 application 的所有监听器实现类 , 如果该实现类还实现了 ApplicationContextAware 接口 , 则将上下文信息设置到该监听器内;第二 , 将 application 中的监听器实现类全部添加到上下文中 。 最后一步才是调用事件广播 。
也正是这个方法形成了不同事件广播形式的分水岭 , 在此方法之前执行的事件广播都是通过multicastEvent 来进行的 , 而该方法之后的方法则均采用 publishEvent 来执行 。 这是因为只有到了 contextL oaded 方法之后 , 上下文才算初始化完成 , 才可通过它的 publishEvent 方法来进行事件的发布 。
自定义 SpringApplicationRunListener
上面我们一起学习了 SpringApplicationRunListener 的基本功能及实现类的源代码 , 现在我们自定义-个 SpringApplicationRunListener 的实现类 。 通过在该实现类中回调方法来处理自己的业务逻辑 。
自定义实现类比较简单 , 可像通常实现一个接口一样 , 先创建类 MyApplicationRunListener , 实现接口 SpringApplicationRunListener 及其方法 。 然后在对应的方法内实现自己的业务逻辑 , 以下示例代码中只简单打印方法名称 。 与普通接口实现唯一不同的是 , 这里需要指定一-个参数依次为 SpringApplication 和 String[ ]的构造方法 , 不然在使用时会直接报错 。