观察者模式
一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。 观察者模式有非常多的应用场景,其中包含消息订阅、事件驱动等,本文会带大家一起探讨观察者模式的基础应用和Spring中的事件驱动机制的使用。
一、SpringBoot基于EventListener和EventObject实现的观察者模式
1、JDK中的EventObject
package java.util;
/**
* @since JDK1.1
*/
public class EventObject implements java.io.Serializable {
private static final long serialVersionUID = 5516075349620653480L;
/**
* 事件发生对象
*/
protected transient Object source;
/**
* 构造器
*/
public EventObject(Object source) {
if (source == null)
throw new IllegalArgumentException("null source");
this.source = source;
}
public Object getSource() {
return source;
}
public String toString() {
return getClass().getName() + "[source=" + source + "]";
}
}
2、Spring中的ApplicationEvent
package org.springframework.context;
import java.util.EventObject;
/**
* ApplicationEvent 抽象类,必须要实现
*/
public abstract class ApplicationEvent extends EventObject {
/**序列号*/
private static final long serialVersionUID = 7099057708183571937L;
/** 发生时间戳 */
private final long timestamp;
/**
* 构造器
*/
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
public final long getTimestamp() {
return this.timestamp;
}
}
3、SpringBoot的抽象SpringApplicatioinEvent 加了个数组参数
/**
* SpringBoot的抽象事件,截至2.0版本有7个实现类,下面具体会讲
*/
public abstract class SpringApplicationEvent extends ApplicationEvent {
private final String[] args;
public SpringApplicationEvent(SpringApplication application, String[] args) {
super(application);
this.args = args;
}
public SpringApplication getSpringApplication() {
return (SpringApplication) getSource();
}
public final String[] getArgs() {
return this.args;
}
}
4、SpringBoot中的事件驱动中的核心Run Listeners
/**
* SpringApplicationRunListener是SpringBoot中的核心接口,
* 在第一步new SpringApplication的时候已经被加载,启动顺序也排第一
* 用于发布事件,具体实现为EventPublishingRunListener
* 父类7个方法分别发布SpringBoot启动过程中7大事件,子类实现中都调用了ApplicationEventMulticaster.multicastEvent(ApplicationEvent e)
*/
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
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();
for (ApplicationListener<?> listener : application.getListeners()) {
// 将所有的listener添加到多播器中
this.initialMulticaster.addApplicationListener(listener);
}
}
@Override
public int getOrder() {
return 0;
}
/**
* 用于发布 ApplicationStartingEvent, 在SpringBoot工程启动的时候
*/
@Override
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
/**
* 一旦Environment环境准备好就会执行,用于发布 ApplicationEnvironmentPreparedEvent
*/
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster
.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
/**
* 一旦ApplicationContext被初始化就会执行,用于发布ApplicationContextInitializedEvent
*/
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster
.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}
/**
* 在ApplicationContext被准备好以后但是没有调用refresh之前调用,用于发布ApplicationPreparedEvent
*/
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
context.addApplicationListener(listener);
}
this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
/**
* ApplicationContext.refresh()方法被调用以后执行,此时CommandLineRunner和ApplicationRunner还没有被调用
* 用于发布ApplicationStartedEvent
*/
@Override
public void started(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
}
/**
* 调用所有的CommandLineRunner和ApplicationRunner后,SpringApplicaton.run()方法接近完成,程序运行成功
* 用于发布ApplicationReadyEvent
*/
@Override
public void running(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
}
/**
* 如果发生失败则调用,用于发布ApplicationFailedEvent 通知应用程序的监听者程序启动失败的消息
*/
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
if (context != null && context.isActive()) {
// Listeners have been registered to the application context so we should
// use it at this point if we can
context.publishEvent(event);
}
else {
// An inactive context may not have a multicaster so we use our multicaster to
// call all of the context's listeners instead
if (context instanceof AbstractApplicationContext) {
for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
.getApplicationListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
this.initialMulticaster.multicastEvent(event);
}
}
private static class LoggingErrorHandler implements ErrorHandler {
private static final Log logger = LogFactory.getLog(EventPublishingRunListener.class);
@Override
public void handleError(Throwable throwable) {
logger.warn("Error calling ApplicationEventListener", throwable);
}
}
}
5、SpringBoot中的多播器SimpleApplicationEventMulticaster
/**
* ApplicationEventMulticaster的简单实现
* 将所有事件广播给所有注册的侦听器,让它自行处理
* EventPublishingRunListener发布每个事件的时候都会调用multicastEvent(ApplicationEvent)进行发布
* 在此方法中会调用所有的Listeners
*/
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@Nullable
private Executor taskExecutor;
@Nullable
private ErrorHandler errorHandler;
public SimpleApplicationEventMulticaster() {
}
public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
setBeanFactory(beanFactory);
}
public void setTaskExecutor(@Nullable Executor taskExecutor) {
this.taskExecutor = taskExecutor;
}
@Nullable
protected Executor getTaskExecutor() {
return this.taskExecutor;
}
public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
@Nullable
protected ErrorHandler getErrorHandler() {
return this.errorHandler;
}
@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);
}
}
}
private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
return ResolvableType.forInstance(event);
}
/**
* 通知SpringApplicationListener 调用的onApplicationEvent
*/
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) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
private boolean matchesClassCastMessage(String classCastMessage, Class<?> eventClass) {
// On Java 8, the message starts with the class name: "java.lang.String cannot be cast..."
if (classCastMessage.startsWith(eventClass.getName())) {
return true;
}
// On Java 11, the message starts with "class ..." a.k.a. Class.toString()
if (classCastMessage.startsWith(eventClass.toString())) {
return true;
}
// On Java 9, the message used to contain the module name: "java.base/java.lang.String cannot be cast..."
int moduleSeparatorIndex = classCastMessage.indexOf('/');
if (moduleSeparatorIndex != -1 && classCastMessage.startsWith(eventClass.getName(), moduleSeparatorIndex + 1)) {
return true;
}
// Assuming an unrelated class cast failure...
return false;
}
}
二、SpringBoot基于EventListener和EventObject的事件驱动模型
以java.util.EventObject为基础,抽象实现出ApplicationEvent, SpringBoot在此基础上,又实现出SpringApplicationEvent抽象类,最后才实现出SpringBoot中的七大事件,代表整个SpringBoot启动的所有生命周期
1. ApplicationStartingEvent
SpringApplication.run()
方法中的第一个状态,从spring.factories
文件中加载完成SpringApplicationRunLinstener,就立即调用listener.starting()
方法发布此事件,
- 代表SpringBoot工程开始启动。在此之前SpringApplication实例已经初始化完成,
- 所有配置在spring.factories中的ApplicationListener,也就是SpringApplicationEvent的监听器也已经被加载。
- 所有配置在spring.factories中的ApplicationContextInitializer被加载到SpringApplication中
- StopWatch启动
- SpringApplicationRunLinstener的唯一实现EventPublishingRunListener被加载
2. ApplicationEnvironmentPreparedEvent
在SpringApplication启动且Environment对象首先可用于检查和修改时发布的事件。
- SpringBoot实例化了ConfigurableEnvironment对象
- 初始化了
spring.profiles
和main(String ... args)
方法传进来的args - 代表Environment环境对象准备完成
- 然后通过调用
listeners.environmentPrepared(environment)
方法发布了此事件 - 接下来会调用Banner打印SpringBoot的彩蛋。
3. ApplicationContextInitializedEvent
在启动SpringApplication并准备好ApplicationContext并调用ApplicationContextInitializers之前(但未加载任何bean定义之前)发布的事件。
- 根据webApplicationType创建了一个
AnnotationConfigServletWebServerApplicationContext
并给其设置Environment为之前创建的ConfigurableEnvironment
对象,创建了DefaultListableBeanFactory - 加载所有配置在spring.factories文件中的SpringBootExceptionReporter
- 调用了
spring.factories
文件中定义并且已经读取到SpringApplication中的ApplicationContextInitializer
- 调用
listeners.contextPrepared(context)
发布了此事件
4. ApplicationPreparedEvent
在SpringApplication启动且ApplicationContext已准备齐全但未刷新时发布的事件。
- 打印启动的profile日志
- 添加了特殊的单例bean到boot(springApplicationArguments和springBootBanner)
- 设置BeanFactory不允许重写Bean定义信息
- 创建了BeanDefinitionLoader并且将SpringBoot工程启动类设置给了BeanDefinitionLoader
- 调用listeners.contextLoaded(context)发布了此事件
5. ApplicationStartedEvent
刷新应用程序上下文后,但在调用任何ApplicationRunner应用程序}和CommandLineRunner命令行运行程序之前,都会发布事件。
-
调用了
AbstractApplicationContext.refresh()
方法。此方法是Spring启动的核心方法,SpringBoot中有很多扩展实现方法。prepareRefresh()
准备上下文,刷新前的工作ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()
刷新内部BeanFactoryprepareBeanFactory(beanFactory)
给BeanFactory设置各种属性postProcessBeanFactory(beanFactory);
允许在上下文子类中对bean工厂进行后处理invokeBeanFactoryPostProcessors(beanFactory)
调用在上下文中注册为bean的BeanFactoryPostProcessor,此环节中调用了其实现类ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()
方法,所有在spring.factories中的AutoConfiguration都在此环节被初始化registerBeanPostProcessors(beanFactory)
注册所有的BeanPostProcessorinitMessageSource()
初始化messageSourceinitApplicationEventMulticaster()
初始化Spring监听者模式的多播器SimpleApplicationEventMulticaster(此多播器和EventPublishRunListener中的多播器是两个不同对象,此为BeanFactory中的单例对象)onRefresh()
在特定上下文子类中初始化其他特殊bean,此过程中调用super.refresh()方法,创建了WebServer,也就是Tomcat容器,但是此时Tomcat只是被注册到BeanFactory中的一个单例对象,并没有被启动。registerListeners()
将所有的Listeners监听器注册到BeanFactory中的多播器SimpleApplicationEventMulticaster
中finishBeanFactoryInitialization()
完成此上下文的bean工厂的初始化,初始化所有剩余的单例bean,比如我们自己创建的Service和Dao等其他的Bean都会在这个阶段初始化- 完成上下文刷新,启动之前创建好的Tomcat。
-
注册ShutDownHook挂钩,用于当前jvm结束进程的时候能优雅的结束此程序
6. ApplicationReadyEvent
表明该应用程序已准备就绪,可以处理请求。事件的来源是SpringApplication本身,但是请注意不要修改其内部状态,因为所有初始化步骤到那时都已完成。
- 此阶段就是调用了
callRuners()
,包含所有的ApplicationRunner
和CommandLineRunner
。
7. ApplicationFailedEvent
SpringApplication启动失败时发布的事件。