设计模式第4式:观察者模式&Spring事件监听机制

前言

观察者模式是一种非常重要的设计模式,在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

总结

我们先从改造一个实际案例来引出观察者模式,随即又在观察者模式上进一步引出事件发布机制,接着我们又分别从源码角度深度解析了事件发布机制的原理。这一系列讲解下来,相信大家对观察者模式和事件监听机制的理解会更加透彻。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值