前言
观察者模式是一种非常重要的设计模式,在JDK和Spring源码中使用非常广泛,而且消息队列软件如kafka、rocketmq等也应用了观察者模式。那么我们就很有必要学习一下观察者模式了。
随后我们来看看大名鼎鼎的事件监听机制,它是基于观察者模式的,但是是由具体的事件来驱动系统的运行,事件监听机制在Spring源码中占有非常重要的位置。
正文
观察者模式是一对多关系,以及松耦合。下面我们跟着《Head First设计模式》的案例的实现,来体会该模式的好处。
气象站案例
现在要开发一个气象站系统,气象站系统包括3个部分:
1、气象站:获取实际气象数据的物理装置;
2、WeatherData对象:追踪来自气象站的数据,并更新布告板。WeatherData对象知道怎么跟气象站联系以获取更新的数据。WeatherData对象随即更新3个布告板的显示;
3、布告板:显示当前天气状况给用户;
我们先来看WeatherData类长什么样?
Class WeatherData {
getTemperature(); // 获取温度
getHumidity(); // 获取湿度
getPressure(); // 获取气压
public void measurementsChanged() {
// 一旦气象数据更新,此方法会被调用
// 我们的代码加在这里
}
先看一个错误示范:
Class WeatherData {
getTemperature(); // 获取温度
getHumidity(); // 获取湿度
getPressure(); // 获取气压
public void measurementsChanged() {
// 调用get方法获取数据
float temp = getTemperature();
float humidity = getHumidity();
float pressure = getPressure();
// 再更新3个布告板
currentDisplay.updata(temp, humidity, pressure);
statisticsDisplay.updata(temp, humidity, pressure);
forecastDisplay.updata(temp, humidity, pressure);
}
这种实现有什么不对吗?我们在更新布告板的时候,使用的是3个布告板的具体对象,我们针对了具体实现编程,这会导致我们以后在增加或删除布告板的时候必须修改程序。到此我们留个悬念,看怎么利用观察者模式来改造这个案例。
引入观察者模式
我们来回忆一下报纸杂志的订阅是怎么回事。
1、报社出版报纸
2、小明向某家报社订阅报纸,报社就会给小明送报纸
3、当小明不想再看报了,就取消订阅,报社则不再给小明送报
4、只要报社还在运营,就一直有人订阅或取消报纸
出版社 + 订阅者 = 观察者模式。我们来转换一下语言,出版者改成“主题”(Subject),订阅者改为“观察者”(Observer)。主题对象管理某些数据,当主题内的数据改变,就会通知观察者。观察者模式定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。下面看下观察者模式的类图:
那么,松耦合到底有什么样的威力?当两个对象之间松耦合,它们依然可以交互,但是不太清楚彼此的细节。观察者模式就提供了一种对象设计,让主题和观察者之间松耦合。主题只知道观察者实现了Observer接口,它不需要知道观察者的具体类是谁,以及其他细节。我们可以随时新增观察者,因为主题唯一依赖的是一个实现了Observer接口的对象列表,在运行时我们可以替换或删除某些观察者。当有新的观察者出现时,主题无需改代码,只需要观察者实现接口,然后注册为观察者即可。
我们可以独立复用主题或观察者,如果我们在其他地方需要使用主题或观察者类,可以轻松复用,因为二者松耦合。
我们可以独立改变主题或观察者,并不会影响另一方。因为它们是松耦合的,所以只要它们的接口仍被遵从,我们就可以自由的改变它们。
设计原则:为了交互对象之间的松耦合设计而努力
改造气象站案例
下面这个图是利用观察者模式改造过的设计图。
1、我们从建立接口开始,主题接口最主要的有3个接口:注册和删除观察者,主题变化后通知所有观察者。
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
观察者接口主要的方法只有一个,就是接收主题的状态变化并作出相关的动作,这里的观察者就是接口主题发来的天气数据后,展示到布告板。
public interface Observer {
public void update(float temp, float humidity, float pressure);
}
还有一个展示接口,属于辅助接口,不重要。
public interface DisplayElement {
public void display();
}
2、再来实现主题接口,WeatherData类实现接口,并持有一个观察者对象的List,一旦主题有变化,就可以遍历List并调用每一个观察者的update方法,达到通知的目的。
public class WeatherData implements Subject{
private float temp;
private float humidity;
private float pressure;
private List<Observer> observers;
public WeatherData() {
this.observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
observers.remove(o);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(temp, humidity, pressure);
}
}
// 这里就是最初预留给我们实现的方法
public void measurementsChanged() {
notifyObservers();
}
// 模拟数据变化
public void setData(float temp, float humidity, float pressure) {
this.temp = temp;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
3、我们再来实现观察者,下面是众多观察者中的一个。观察者除了要实现Observer接口的方法外,还要将自己注册给主题,在这个例子中,观察者持有一个主题对象,并在实例化时将自己注册到主题中去。其实这个注册的动作可以有很多形式,目的都是将观察者注册进主题的List列表中。
public class CurrentDisplay implements Observer, DisplayElement{
private float temp;
private float humidity;
private Subject subject;
// 通过构造方法将自己注册到Subject
public CurrentDisplay(Subject s) {
this.subject = s;
subject.registerObserver(this);
}
@Override
public void display() {
System.out.println("temp: " + this.temp + ", humidity: " + this.humidity);
}
@Override
public void update(float temp, float humidity, float pressure) {
this.temp = temp;
this.humidity = humidity;
}
}
观察者模式在JDK中的应用
JDK util包里自带了Observable主题类和Observer观察者接口,我们可以使用它们来实现观察者模式。但是在JDK9之后就不再推荐使用了,这里就不再深入介绍了,使用原理和上面的差不多,大家有兴趣可以看下。
事件监听机制是什么
软件开发中,触发某事件并对事件作出反应是非常常见的开发模式。它是基于观察者模式,加入了“事件”元素,主题发布事件,观察者(也可以叫监听者)监听特定的事件并作出反应。Java对此也提供了支持,java.util包里面提供了事件类和事件监听者接口,Spring对此做了很好的实现,待会来看。
public class EventObject implements java.io.Serializable {
protected transient Object source;
public EventObject(Object source) {
if (source == null)
throw new IllegalArgumentException("null source");
this.source = source;
}
}
EventObject类有一个Object类型的属性,一般传入发布事件的主题类对象。
public interface EventListener {
}
事件监听者接口空着,由子类实现。
事件监听机制在Spring中的应用
Spring在启动过程中会有很多节点,比如context准备启动了、context启动完成了、context启动失败了,Spring将这些节点都定义为“事件”。这些事件发生后,监听者就会收到通知,进而作出响应的动作。Spring的启动流程可以参考本人Spring源码解析系列,其中启动过程解析博客:IOC容器启动过程详解。
1、主题是谁
Spring提供了一个事件发布接口,我们都知道发布事件是主题(Subject)干的事情,那么在Spring中谁来扮演主题这个角色呢?
@FunctionalInterface
public interface ApplicationEventPublisher {
void publishEvent(Object event);
}
答案是IOC容器本身,应用上下文ApplicationContext接口继承了ApplicationEventPublisher接口,并在实现类AbstractApplicationContext中实现了publishEvent抽象方法。
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
private ApplicationEventMulticaster applicationEventMulticaster;
@Override
public void publishEvent(Object event) {
publishEvent(event, null);
}
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
...
applicationEvent = (ApplicationEvent) event;
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
...
}
}
我们通过看源码,发现IOC容器作为主题,调用publishEvent方法发布事件,publishEvent又调用了内部的同名重载方法,最终将事件发布委托给了ApplicationEventMulticaster接口的multicastEvent方法。这种委托方式在Spring中非常常见,毕竟Spring启动有很多步骤,如果事情都是自己做,那么代码将会又臭又长,IOC容器只关注主体流程,细枝末节的处理就交给其他类了。
我们再来看看事件发布器是怎么初始化的,在IOC容器启动的refresh方法(在AbstractApplicationContext类中)中有一步是专门初始化事件发布器的。
public void refresh() {
...
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
...
}
方法也比较简单,如果容器中已经有事件发布器了,就从容器中拿出来给属性applicationEventMulticaster赋值;如果容器中没有,则new一个SimpleApplicationEventMulticaster对象出来。上面讲的委托实际上就是委托给SimpleApplicationEventMulticaster实现类了。
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}
再来看一眼SimpleApplicationEventMulticaster中的方法multicastEvent方法,看到方法中的for循环了吗,这里就是遍历所有观察者(监听者),然后调用它们的监听方法。看到这里,有没有点感觉?事件监听机制的底层还是观察者模式。
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
...
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
}
2、事件
Java中的事件类是EventObject,它有一个重要属性source保存是哪个类发布的事件。
public class EventObject implements java.io.Serializable {
/**
* The object on which the Event initially occurred.
*/
protected transient Object source;
}
Spring中的事件类是ApplicationEvent,加了一个时间戳属性
public abstract class ApplicationEvent extends EventObject {
private final long timestamp;
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
}
3、监听器
Java中的监听器只是一个空接口。
public interface EventListener {
}
Spring中的监听器是ApplicationListener,它继承了Java中的EventListener接口。它拥有一个泛型参数,只接收事件类型,表示监听哪一类事件;它有一个抽象方法,用于实现监听到事件发生后的处理逻辑,实现类重点实现了这个方法;它还是一个函数式接口。
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}
再来介绍2个子接口,它们继承ApplicationListener接口。SmartApplicationListener接口设计了2个方法,这2个方法用来判断监听器本身是否支持给定的eventType或sourceType。这2个方法有什么用呢?比如在发布事件A时,需要先筛选出监听事件A的所有监听器,筛选过程就用到这2个方法。
public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
/**
* Determine whether this listener actually supports the given event type.
*/
boolean supportsEventType(Class<? extends ApplicationEvent> eventType);
/**
* Determine whether this listener actually supports the given source type.
*/
default boolean supportsSourceType(@Nullable Class<?> sourceType) {
return true;
}
。。。
}
子接口GenericApplicationListener继续关注supportsEventType方法。
public interface GenericApplicationListener extends SmartApplicationListener {
@Override
default boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return supportsEventType(ResolvableType.forClass(eventType));
}
boolean supportsEventType(ResolvableType eventType);
}
子类GenericApplicationListenerAdapter实现了supportsEventType方法,用来筛选监听器,下面小节会讲。注意这个类是一个监听器适配器类,它用于解析监听器对象。
public class GenericApplicationListenerAdapter implements GenericApplicationListener {
// 2个属性,一个是监听器对象,另一个是监听的事件类型
private final ApplicationListener<ApplicationEvent> delegate;
private final ResolvableType declaredEventType;
// 构造器将传入的listener进行解析,填充2个属性值
public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) {
this.delegate = (ApplicationListener<ApplicationEvent>) delegate;
this.declaredEventType = resolveDeclaredEventType(this.delegate);
}
@Override
public boolean supportsEventType(ResolvableType eventType) {
// 如果监听器实现了父接口,就交给实现类处理
if (this.delegate instanceof GenericApplicationListener) {
return ((GenericApplicationListener) this.delegate).supportsEventType(eventType);
}
// 如果监听器实现了父接口,就交给实现类处理
else if (this.delegate instanceof SmartApplicationListener) {
Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
}
// 如果监听事件为空,或者当前监听器监听的事件类型是给定事件类型的父类
// A.isAssignableFrom(B)表示A和B是同一个类(接口)或者A是B的父类(父接口)
else {
return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
}
}
。。。
}
4、事件发布器
我们来看下Spring中的监听器们是怎么被注册到容器中的,以及事件是怎么发布的。上文我们提到了Spring其实是将事件发布动作委托给了SimpleApplicationEventMulticaster类,就来看看被委托的类是什么样的。
顶层接口设计了一些增删监听器的方法,以及发布事件的方法。
public interface ApplicationEventMulticaster {
void addApplicationListener(ApplicationListener<?> listener);
void addApplicationListenerBean(String listenerBeanName);
void removeApplicationListener(ApplicationListener<?> listener);
void removeApplicationListenerBean(String listenerBeanName);
void removeApplicationListeners(Predicate<ApplicationListener<?>> predicate);
void removeApplicationListenerBeans(Predicate<String> predicate);
void removeAllListeners();
void multicastEvent(ApplicationEvent event);
void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}
抽象实现类实现了增删监听器的方法,实质是将监听器对象放进内部类的Set集合中。
public abstract class AbstractApplicationEventMulticaster
implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.defaultRetriever) {
// 添加监听器到内部类
this.defaultRetriever.applicationListeners.add(listener);
}
}
}
最底层的类继承了上面的抽象类并实现了发布事件的方法。下面摘取了部分主要代码。
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@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));
// 根据事件对象及类型获取相关的监听器,它最终调用retrieveApplicationListeners方法
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
...
invokeListener(listener, event);
}
}
}
getApplicationListeners方法在其父类AbstractApplicationEventMulticaster中,并最终调用了retrieveApplicationListeners方法。supportsEvent方法就是用来筛选的,用到的GenericApplicationListenerAdapter类在上一小节也讲过。
private Collection<ApplicationListener<?>> retrieveApplicationListeners(...) {
// 遍历内部类中的Set集合,找到匹配的监听器
for (ApplicationListener<?> listener : listeners) {
if (supportsEvent(listener, eventType, sourceType)) {
...
allListeners.add(listener);
}
}
return allListeners;
}
protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
// 这里先判断监听器的类型,如果是GenericApplicationListener类型,就直接转换成该类型,否则用GenericApplicationListenerAdapter类型包装一下。
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
// 返回2个类型匹配方法的结果
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
筛选到对应的监听器后,就该发布事件了,我们再回到multicastEvent方法的for循环。
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
// 触发监听器
invokeListener(listener, event);
}
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
...
else {
// Spring很喜欢搞这样的方法嵌套
doInvokeListener(listener, event);
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 终于到头了,这里就是调用监听器的onApplicationEvent方法
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
...
}
SpringBoot中的事件监听机制
SpringBoot使用的事件机制核心还是上面讲到的Spring这一套事件监听机制。我们使用SpringBoot事件机制时,定义好了监听器后,将其类型在spring.factories文件中,SpringBoot在启动时会读取这个文件。SpringBoot的事件监听机制只是在Spring的基础上,加上了配置文件读取这部分。我们来看源码。
1、SPI机制
SPI机制说白了就是将使用到的类写在spring.factories文件中,再配合一个方法就能将类加载到容器中。我们从SpringBoot的启动类的启动方法run开始。
public class SpringApplication {
// run方法传入main方法所在的类,及main方法参数
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
// 实例化本身,并调用重载的run方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
我们再来看下实例化做了什么,它从spring.factories文件中拿到key为ApplicationListener的所有配置值,实例化后放进属性listeners中。
public class SpringApplication {
private List<ApplicationListener<?>> listeners;
// 构造方法
public SpringApplication(Class<?>... primarySources) {
this((ResourceLoader)null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 设置listeners属性
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
}
}
好神奇啊,SpringBoot一启动就能把所有的监听器加载到内存中。起作用的就是下面这个方法,传入一个类型A,它就会找到所有spring.factories文件中以类型A为key的所有值,并实例化。
this.getSpringFactoriesInstances(ApplicationListener.class);
spring.factories配置文件很简单,就是key-value键值对。key就是顶层接口全类名,value就是一堆实现类的全类名,以逗号隔开。仔细看,下面这个监听器接口就是Spring的接口。
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener
2、发布事件
实例化后,再回到run方法。下面这个就是SpringBoot的启动方法,我们只摘取一小部分和事件发布相关的方法。
public ConfigurableApplicationContext run(String... args) {
...
// 使用SPI获取
SpringApplicationRunListeners listeners = getRunListeners(args);
// 发布开始启动事件
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
...
// 发布已启动事件
listeners.started(context, timeTakenToStartup);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
// 发布启动失败事件
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
}
我们看到,在run方法中,要发布很多事件都是由SpringApplicationRunListeners来执行的,我们就来看看它的源码。它主要是使用了函数式编程来实现
class SpringApplicationRunListeners {
// list属性
private final List<SpringApplicationRunListener> listeners;
// 下面设计了一堆方法,定义了SpringBoot启动的不同阶段,它们最终都调用了doWithListeners方法
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
doWithListeners((listener) -> listener.starting(bootstrapContext));
}
void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
doWithListeners((listener) -> listener.environmentPrepared(bootstrapContext, environment));
}
void contextPrepared(ConfigurableApplicationContext context) {
doWithListeners((listener) -> listener.contextPrepared(context));
}
void contextLoaded(ConfigurableApplicationContext context) {
doWithListeners((listener) -> listener.contextLoaded(context));
}
void started(ConfigurableApplicationContext context, Duration timeTaken) {
doWithListeners((listener) -> listener.started(context, timeTaken));
}
void ready(ConfigurableApplicationContext context, Duration timeTaken) {
doWithListeners((listener) -> listener.ready(context, timeTaken));
}
void failed(ConfigurableApplicationContext context, Throwable exception) {
doWithListeners((listener) -> callFailedListener());
}
// 这是个模板方法,使用了函数式编程的思想,第2个参数是重点
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
Consumer<StartupStep> stepAction) {
// 这里循环执行SpringApplicationRunListener中的lambda表达式方法
this.listeners.forEach(listenerAction);
}
}
我们再来看看属性List<SpringApplicationRunListener> listeners中的泛型,注意它没有s。它是个接口,同样规定了SpringBoot启动的不同阶段,抽象方法在实现类中实现。
public interface SpringApplicationRunListener {
default void starting(ConfigurableBootstrapContext bootstrapContext) {
}
default void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
ConfigurableEnvironment environment) {
}
default void contextPrepared(ConfigurableApplicationContext context) {
}
default void contextLoaded(ConfigurableApplicationContext context) {
}
default void started(ConfigurableApplicationContext context, Duration timeTaken) {
}
default void ready(ConfigurableApplicationContext context, Duration timeTaken) {
}
default void failed(ConfigurableApplicationContext context, Throwable exception) {
}
}
实现类EventPublishingRunListener 完全就是调用Spring那一套事件发布机制了。
class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
// 这个属性就是Spring的事件发布器
private final SimpleApplicationEventMulticaster initialMulticaster;
// 构造方法实例化事件发布器
EventPublishingRunListener(SpringApplication application, String[] args) {
this.initialMulticaster = new SimpleApplicationEventMulticaster();
}
// 下面的一系列方法就是发布不同的事件了
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
multicastInitialEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
}
@Override
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
ConfigurableEnvironment environment) {
multicastInitialEvent(
new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
multicastInitialEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
multicastInitialEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
@Override
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context, timeTaken));
AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
}
@Override
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context, timeTaken));
AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
context.publishEvent(event);
}
// 重点方法
private void multicastInitialEvent(ApplicationEvent event) {
// 看下这个发布事件的方法,就是Spring中的方法
this.initialMulticaster.multicastEvent(event);
}
}
至此,大家是不是有一种豁然开朗的感觉?那么我们再回到run方法,看下是怎么获取事件发布器的。
SpringApplicationRunListeners listeners = getRunListeners(args);
private SpringApplicationRunListeners getRunListeners(String[] args) {
// SPI获取实例
List<SpringApplicationRunListener> listeners = getSpringFactoriesInstances(SpringApplicationRunListener.class,
argumentResolver);
// 再封装一层返回
return new SpringApplicationRunListeners(logger, listeners, this.applicationStartup);
}
下面就是spring.factories的内容,我们看实现类就是上面说的EventPublishingRunListener。
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
总结
我们先从改造一个实际案例来引出观察者模式,随即又在观察者模式上进一步引出事件发布机制,接着我们又分别从源码角度深度解析了事件发布机制的原理。这一系列讲解下来,相信大家对观察者模式和事件监听机制的理解会更加透彻。