1.监听器
触发事件时通过监听器完成业务逻辑。
1.系统类监听器
// 可以注册自己感兴趣的事件的监听器,当有事件发生时,会自动根据注册的事件类型
// 来进行过滤和触发事件
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
触发一个application context的事件
void onApplicationEvent(E event);
}
其实现类如ContextRefreshListener,注册的事件就是ContextRefreshEvent。
private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
FrameworkServlet.this.onApplicationEvent(event);
}
}
2.运行时监听器 SpringApplicationRunListener
SpringApplicationRunListener 接口规定了 SpringBoot 的生命周期,在各个生命周期广播相应的事件,调用实际的 ApplicationListener 类。通过对 SpringApplicationRunListener 的分析,也可以对 SpringBoot 的整个启动过程的理解会有很大帮助。
public interface SpringApplicationRunListener {
//当run方法首次启动时立即调用。可用于非常早期的初始化。
void starting();
//在准备好环境后,但在创建ApplicationContext之前调用。
void environmentPrepared(ConfigurableEnvironment environment);
//在创建和准备好ApplicationContext之后,但在加载源之前调用。
void contextPrepared(ConfigurableApplicationContext context);
//在加载应用程序上下文后但刷新之前调用
void contextLoaded(ConfigurableApplicationContext context);
//上下文已刷新,应用程序已启动,但尚未调用commandlinerunner和applicationrunner。
void started(ConfigurableApplicationContext context);
//在运行方法完成之前立即调用,此时应用程序上下文已刷新,
//并且所有commandlinerunner和applicationrunner都已调用。
//2.0 才有
void running(ConfigurableApplicationContext context);
//在运行应用程序时发生故障时调用。2.0 才有
void failed(ConfigurableApplicationContext context, Throwable exception);
}
3.SpringApplicationRunListeners
SpringApplicationRunListeners 是SpringApplicationRunListener的集合,里面包括了很多SpringApplicationRunListener实例;SpringApplication 类实际上使用的是 SpringApplicationRunListeners 类,与 SpringApplicationRunListener 生命周期相同,调用各个周期的 SpringApplicationRunListener 。然后广播相应的事件到 ApplicationListener。
2.事件events
相当于是容器启动的各个时间点
1.抽象类 ApplicationEvent
// 该抽象类需要被具体的事件实现才又意义,这也是设置为abstract的原因
public abstract class ApplicationEvent extends EventObject {
// 事件发生的时间点
private final long timestamp;
// 构造函数
public ApplicationEvent(Object source) {
// 设置事件源码
super(source);
this.timestamp = System.currentTimeMillis();
}
// 返回事件发生的时间
public final long getTimestamp() {
return this.timestamp;
}
}
spring中事件主要分为两类,一类是和应用程序上下文相关的事件,一类是和应用程序上下文处理请求相关的事件。
1.应用程序上下文相关的事件
抽象类
public abstract class ApplicationContextEvent extends ApplicationEvent {
/**
* Create a new ContextStartedEvent.
* @param source the {@code ApplicationContext} that the event is raised for
* (must not be {@code null})
*/
public ApplicationContextEvent(ApplicationContext source) {
super(source);
}
/**
* Get the {@code ApplicationContext} that the event was raised for.
*/
public final ApplicationContext getApplicationContext() {
return (ApplicationContext) getSource();
}
}
具体实现
2.
EventObject 事件对象
ApplicationEvent 应用事件
SpringApplicationEvent Spring中的系统事件
ApplicationPreparedEvent 该事件表示:应用已经准备好
ApplicationReadyEvent 该事件表示:应用已经就绪
ApplicationStartedEvent 该事件表示:容器已经启动
ApplicationFailedEvent 该事件表示:容器启动失败
ApplicationEnvironmentPreparedEvent 该事件表示:应用上下文环境已经准备完成
ApplicationContextInitializedEvent 该事件表示:应用启动完成
starting: 环境一启动就发出
environmentPrepared: 环境已准备妥当,即 已将系统和自定义的的一些属性已加载到容器内
contextInitialized:springboot已经启动,并且准备好了上下文,这个是在加载bean之前发布的
prepared:应用上下文已经创建完毕,但bean还没有完全加载完成
started: springboot已经将bean实例化完成了,但是还没调用CommandLineRunner和ApplicationRunner 这两个接口
ready:CommandLineRunner和ApplicationRunner 调用完毕后发出
failed:启动运行中如果发生错误会发送该事件
3.广播器ApplicationEventMulticaster
可以将当前事件广播给感兴趣的监听器,也就是查找感兴趣的监听器,然后完成监听器方法的执行
// 通过该接口,可以实现管理一组ApplicationListener对象,并且可以给他们发布事件,ApplicationEventPublisher
// 可以委派ApplicationEventMulticaster来真正的发布事件
public interface ApplicationEventMulticaster {
// 添加一个监听所有事件的监听器
void addApplicationListener(ApplicationListener<?> listener);
// 添加一个监听所有事件的监听器的spring bean
void addApplicationListenerBean(String listenerBeanName);
// 从事件通知列表中删除一个监听器
void removeApplicationListener(ApplicationListener<?> listener);
// 从事件通知列表中删除一个监听器
void removeApplicationListenerBean(String listenerBeanName);
// 删除事件广播器中所有的事件监听器
void removeAllListeners();
// 广播给定的application事件到合适的监听器
void multicastEvent(ApplicationEvent event);
// 广播给定的application事件到合适的监听器
void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}
4.触发机制
定义在SpringApplicationRunListener 接口的这些方法
第一种触发机制
starting
调用EventPublishingRunListener的starting方法,这个类是SpringApplicationRunListener唯一的实现类。
然后调用SimpleApplicationEventMulticaster的multicastEvent方法。这个类是EventPublishingRunListener的一个成员变量
在这个方法中会获得对当前事件感兴趣的监听器 当前事件是ApplicationStartingEvent。
对这个事件感兴趣的监听器有4个
1.LoggingApplicationListener
发现这个类没有对任何事件感兴趣,但是它实现了一个接口
这个接口对 ApplicationEvent事件感兴趣
ApplicationEvent是SpringApplicationEvent的父类,SpringApplicationEvent是ApplicationStartingEvent的父类,所以该监听器相当于对当前事件ApplicationStartingEvent感兴趣,所以会被找到。
2.BackgroundPreinitializer
再来看一个不对这个事件感兴趣的监听器 比如FileEncodingApplicationListener
可以看出这个监听器对ApplicationEnvironmentPreparedEvent感兴趣。所以当这个事件发生时,这个监听器不会启动
找到监听之后,就会调用invokeListener(listener, event)方法
最终会调用每个listener的onApplicationEvent方法 这个doInvokeListener方法在SimpleApplicationEventMulticaster这个类中 这个类是EventPublishingRunListener的一个成员变量
例如LoggingApplicationListener类的onApplicationEvent方法
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationStartingEvent) {
onApplicationStartingEvent((ApplicationStartingEvent) event);
}
else if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
}
else if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent((ApplicationPreparedEvent) event);
}
else if (event instanceof ContextClosedEvent
&& ((ContextClosedEvent) event).getApplicationContext().getParent() == null) {
onContextClosedEvent();
}
else if (event instanceof ApplicationFailedEvent) {
onApplicationFailedEvent();
}
}
此时会进入第一个判断 ,执行相关操作。
总结下
主启动类构造函数中注册监听器,run方法中先注册run监听器,然后触发事件,通过广播器进行广播,找到对当前事件感兴趣的监听器。调用监听器方法完成业务逻辑。
5.自定义监听器监听系统事件
第一步:自定义一监听器
//实现监听器接口 指明感兴趣的事件
public class MyListener implements ApplicationListener<ApplicationStartingEvent> {
//@Override
//public void onApplicationEvent(MyEvent event) {
// System.out.println("1111");
// System.out.println(event);
//}
//重写方法 当事件触发时调用
@Override
public void onApplicationEvent(ApplicationStartingEvent event) {
//获取到主启动类
System.out.println(event.getSpringApplication().getMainApplicationClass());
System.out.println(event);
}
}
第二步:创建spring.factories文件,指明自定义监听器的路径
第三步:主启动类启动,触发ApplicationStartingEvent
6.自定义事件
1创建自定义事件类 继承ApplicationEvent ,重写构造方法
public class MyEvent extends ApplicationEvent {
/**
* Create a new {@code ApplicationEvent}.
*
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
*/
public MyEvent(Object source) {
super(source);
}
}
2.修改自定义的监听器,监听这个事件
3.触发事件
这里context可以调用publishEvent,是因为applicationcontext继承了一个事件发布接口,该类中有方法可以发布事件。方法实现在AbstractApplicationContext类中
也是调用这个方法 获取广播器 实现广播