前言
观察者模式是GOF提出的23种设计模式之一,应用范围很广泛,网络上有太多资料介绍观察者模式,举例也很生动形象,理解起来并不困难。
百度百科这样定义观察者模式:观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
放到生活中的例子也有很多,例如,在微信上订阅了某个公众号,当公众号运营者发布新内容时,就会将消息推送到订阅者的微信上。
Spring中提供了一套事件监听机制(算是观察者模式的实现),既在内部使用,也对外提供给开发者使用,在日常开发中经常会用到。
例如如下代码:
/**
* 定义事件消息
*/
public class MyApplicationEvent extends ApplicationEvent {
private String message;
public MyApplicationEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
/**
* 定义监听器,并且使用@Component注解,Spring会将该listener注册到广播器
*/
@Component
public class MyApplicationEventListener implements ApplicationListener<MyApplicationEvent> {
@Override
public void onApplicationEvent(MyApplicationEvent event) {
System.out.println(event.getMessage() + ",停止交易!");
}
}
/**
* 业务类,感知了ApplicationContext之后,就可以使用applicationContext.publishEvent(event)在业务代码中发布事件消息了
*/
@Service
public class MyBiz implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void bizMethod(boolean foundPolice) {
if (foundPolice) {
// 自定义事件消息内容
MyApplicationEvent event = new MyApplicationEvent(this, "有内鬼");
// 发布事件消息
applicationContext.publishEvent(event);
}
}
}
当业务代码运行applicationContext.publishEvent(event)后,事件消息就会被Spring发布给监听器MyApplicationEventListener,打印出"有内鬼,停止交易!"
使用起来比较简单,但是Spring是如何实现这个过程的呢?下面通过解析源码来看看这个过程。
源码
源码基于Spring5.3.16版本,不同版本有轻微差异,整体逻辑一致。
Spring提供的事件监听机制,不仅仅供开发者在业务代码中使用,Spring源码内部也在大量使用。
这里不以Spring内部如何使用监听器为重点,以开发者业务逻辑使用监听器为重点,将事件监听机制的源码分为4个重要过程:
- Spring上下文对象AbstractApplicationContext初始化事件广播器ApplicationEventMulticaster
- 事件广播器注册监听器ApplicationListener
- 业务代码调用Spring上下文对象发布事件
- 广播器选择"感兴趣"的监听器,执行监听器处理事件的逻辑
1、初始化事件广播器
Spring容器在启动过程中,会进入Spring上下文对象的refresh()方法,这个方法很重要,因为其贯穿了整个容器的生命线。
给Spring上下文对象AbstractApplicationContext初始化事件广播器就是在refresh()方法其中一步完成的,具体位置是在initApplicationEventMulticaster()过程。
// 代码位置:org.springframework.context.support.AbstractApplicationContext#refresh
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// ...代码省略
try {
// ...代码省略
// 初始化事件广播器
initApplicationEventMulticaster();
// ...代码省略
// 注册监听器ApplicationListener
registerListeners();
// ...代码省略
}
// ...代码省略
}
}
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 如果容器中存在"applicationEventMulticaster",那就获取返回
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
// 如果容器中不存在"applicationEventMulticaster",那就创建一个SimpleApplicationEventMulticaster
// 并且赋值给上下文对象的applicationEventMulticaster属性
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
方法initApplicationEventMulticaster()中,为Spring上下文对象AbstractApplicationContext的属性applicationEventMulticaster,初始化了一个事件广播器SimpleApplicationEventMulticaster,而SimpleApplicationEventMulticaster继承了抽象类AbstractApplicationEventMulticaster,所以这个广播器对象初始化完成后,内部会存在一个属性defaultRetriever,用于存储注册到广播器的listeners。
/**
* SimpleApplicationEventMulticaster继承了抽象类AbstractApplicationEventMulticaster
*/
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
// ... 代码省略
}
public abstract class AbstractApplicationEventMulticaster
implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
// 存放监听器listeners的容器
private final DefaultListenerRetriever defaultRetriever = new DefaultListenerRetriever();
// ...代码省略
/**
* defaultRetriever添加listener的方式一,直接添加一个ApplicationListener对象,一般由Spring内部使用
* 比如ApplicationContextClosedListener
*/
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.defaultRetriever) {
// Explicitly remove target for a proxy, if registered already,
// in order to avoid double invocations of the same listener.
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
/**
* 除了方式一以外,还支持基于beanName方式,添加listener,这种方式一般是业务中自定义Listener用到的
* 当需要该listener时,会从容器获取或创建该beanName对应的listener bean
* 比如上面代码示例中的MyApplicationEventListener
*/
@Override
public void addApplicationListenerBean(String listenerBeanName) {
synchronized (this.defaultRetriever) {
this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
this.retrieverCache.clear();
}
}
// ...代码省略
}
由上面代码可见,初始化事件广播器完成后,容器中存在的几个重要对象的关系如下:
2、注册监听器
同第1步初始化事件广播器一样,为事件广播器注册监听器listeners也是Spring在refresh()方法中完成的,在第1步中展示的refresh()源码中,已经通过注释指明了注册监听器的发生位置所在,即执行refresh()中的registerListeners()过程。
在这个过程中,会进行两种类型的listeners注册:
- 一种是一般由Spring内部添加的listeners,通过调用
addApplicationListener(ApplicationListener<?> listener)方法注册到事件广播器的listener; - 另一种是通过获取容器中的
ApplicationListener类型的beanName,调用addApplicationListenerBean(String listenerBeanName)方法,将beanName先加入到事件广播器存储listeners的容器中,这些beanName对应的bean此时在容器中还未被创建,当后续需要用到listener的时候,会从容器中创建这个beanName对应的listener。代码示例中的MyApplicationEventListener就是通过这种方式。
// 代码位置:org.springframework.context.support.AbstractApplicationContext#registerListeners
protected void registerListeners() {
// Register statically specified listeners first.
for (ApplicationListener<?> listener : getApplicationListeners()) {
// 第一种方式,直接注册listener类型的对象到事件广播器
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
// 第二种方式,获取容器中此时存在的所有ApplicationListener类型的beanName
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
// 将beanName注册到事件广播器 注意:getBeanNamesForType只是根据类型从BeanDefinition中获取beanName,并未创建出bean
// 何时创建这些ApplicationListener bean?当需要监听器时,那何时需要监听器?即当发布事件到广播器时
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// ...代码省略
}
3、发布事件到事件广播器
前面两步都是Spring在内部帮我们完成的,初始化了一个广播器、注册了我们自定义的ApplicationListener。
那么如何在业务逻辑中发布事件?
如果能直接获取到Spring上下文对象AbstractApplicationContext中的SimpleApplicationEventMulticaster,那就调用这个对象的multicastEvent(ApplicationEvent event)就可以发布事件了。可是AbstractApplicationContext并没有提供给外部获取SimpleApplicationEventMulticaster的getter方法,SimpleApplicationEventMulticaster是Spring内部操作的对象。
AbstractApplicationContext中的SimpleApplicationEventMulticaster对象获取不到,那么该如何发布事件?
ApplicationContext类型对象是Spring提供给外部的上下文对象,里面封装了很多方便外部调用的接口,常见的例如,根据名称获取bean的方法getBean(String name),根据类型获取bean的方法getBean(Class<T> requiredType)等等,我们都是通过Spring上下文对象ApplicationContext完成的,但是实际上,Spring上下文对象只用来传递外部的方法调用,真正处理逻辑的是上下文对象中包含的各个组件,例如处理getBean方法,就是调用上下文对象包含的BeanFactory对象的getBean方法完成的。
为了外部很方便的使用事件监听机制,Spring也在上下文对象中提供了关于事件的一些方法:
- addApplicationListener(ApplicationListener<?> listener) 给事件广播器注册监听器的方法
- publishEvent(ApplicationEvent event) 发布事件方法
所以,发布事件只需要获取到Spring的上下文对象就行了,Spring提供了上下文感知接口ApplicationContextAware,方便业务逻辑中获取到Spring上下文对象。
/**
* 业务类,感知了ApplicationContext之后,就可以使用applicationContext.publishEvent(event)在业务代码中发布事件消息了
*/
@Service
public class MyBiz implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void bizMethod(boolean foundPolice) {
if (foundPolice) {
// 自定义事件消息内容
MyApplicationEvent event = new MyApplicationEvent(this, "有内鬼");
// 发布事件消息
applicationContext.publishEvent(event);
}
}
}
4、广播器选择监听器,处理事件
紧接着第3步,调用ApplicationContext对象的publishEvent(event)方法,上下文对象会将事件交给事件广播器,由事件广播器对象发布事件。
然后在事件广播器中选择对该事件"感兴趣"的监听器,处理事件。
通过上面第2步,可以知道广播器中注册了众多listeners,如何判断当前发布的事件是否是某个listener感兴趣的呢?然后交给这个listener去处理事件,这里是一个重点。
// 代码位置:org.springframework.context.support.AbstractApplicationContext#publishEvent(org.springframework.context.ApplicationEvent)
@Override
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
// ...代码省略
// 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);
}
// ...代码省略
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
// getApplicationListeners方法就是根据事件类型查找感兴趣的listener,这里标记为①
// 然后一个个遍历返回的listener,处理事件
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
// 如果executor不为空,支持异步调用listener执行事件处理逻辑
executor.execute(() -> invokeListener(listener, event));
}
else {
// 默认情况下executor没有配置,同步调用listener执行事件处理逻辑,这里标记为②
invokeListener(listener, event);
}
}
}
// ①
// ps:①表示当前方法处于上面标记为①的方法栈中
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// Potential new retriever to populate
CachedListenerRetriever newRetriever = null;
// ...代码省略 为了快速多次快速获取listeners,Spring在这里设计了缓存,可以先不管
// 检索对事件感兴趣的listeners
return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}
// ①
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) {
// 本方法内的retriever变量是用来做缓存的,可以不关注retriever的逻辑
List<ApplicationListener<?>> allListeners = new ArrayList<>();
Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);
Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
synchronized (this.defaultRetriever) {
// 获取事件广播器中注册了的所有applicationListeners
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
// 获取事件广播器中注册了的所有ApplicationListener类型的beanName列表
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
// Add programmatically registered listeners, including ones coming
// from ApplicationListenerDetector (singleton beans and inner beans).
for (ApplicationListener<?> listener : listeners) {
// 先遍历注册的listeners,一个个判断listener是否支持当前事件,这里标记为③
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
filteredListeners.add(listener);
}
// 如果支持,就是要找的listener,添加到要返回的allListeners列表
allListeners.add(listener);
}
}
// Add listeners by bean name, potentially overlapping with programmatically
// registered listeners above - but here potentially with additional metadata.
if (!listenerBeans.isEmpty()) {
ConfigurableBeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
try {
// 再遍历所有的ApplicationListener类型的beanName列表
// 从容器中获取listenerBeanName对应的beanType,先通过判断beanType的泛型类型是否是eventType类型以及其父类型。
// 因为这个过程不用实例化listenerBeanName对应的bean,可以避免创建不对事件感兴趣的listener
// 标记为④
if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
// 根据listenerBeanName从容器中获取bean,如果容器中不存在就会创建bean
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
// listener已经有了,那就走和上面③位置一样的判断逻辑 supportsEvent(listener, eventType, sourceType)
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
if (beanFactory.isSingleton(listenerBeanName)) {
filteredListeners.add(listener);
}
else {
filteredListenerBeans.add(listenerBeanName);
}
}
// 如果支持,就是要找的listener,添加到要返回的allListeners列表
allListeners.add(listener);
}
}
else {
// Remove non-matching listeners that originally came from
// ApplicationListenerDetector, possibly ruled out by additional
// BeanDefinition metadata (e.g. factory method generics) above.
Object listener = beanFactory.getSingleton(listenerBeanName);
if (retriever != null) {
filteredListeners.remove(listener);
}
allListeners.remove(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Singleton listener instance (without backing bean definition) disappeared -
// probably in the middle of the destruction phase
}
}
}
// 对所有的listener排序,order数值越大,优先级越低
AnnotationAwareOrderComparator.sort(allListeners);
if (retriever != null) {
if (filteredListenerBeans.isEmpty()) {
retriever.applicationListeners = new LinkedHashSet<>(allListeners);
retriever.applicationListenerBeans = filteredListenerBeans;
}
else {
retriever.applicationListeners = filteredListeners;
retriever.applicationListenerBeans = filteredListenerBeans;
}
}
// 返回排序好的allListeners
return allListeners;
}
// ① -> ③
protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
// 判断listener是否是GenericApplicationListener类型,如果不是,就包装成适配器类型GenericApplicationListenerAdapter
// new GenericApplicationListenerAdapter()时,会初始化适配器对象的delegate、declaredEventType属性
// delegate就是当前listener自身,declaredEventType是解析当前listener的泛型类型,封装成的一个ResolvableType对象
// 例如上面示例代码 MyApplicationEventListener implements ApplicationListener<MyApplicationEvent>,declaredEventType就是获取ApplicationListener<MyApplicationEvent>中的泛型类型MyApplicationEvent,而封装的一个ResolvableType对象
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
// 如果业务listener没有实现GenericApplicationListener,而是ApplicationListener(例如上面示例代码MyApplicationEventListener),就会进入GenericApplicationListenerAdapter的判断逻辑
// GenericApplicationListenerAdapter对象执行"&&"后半段supportsSourceType(sourceType),默认返回true
// 这里关注"&&"的前半段supportsEventType(eventType)
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
// ① -> ③
@Override
@SuppressWarnings("unchecked")
public boolean supportsEventType(ResolvableType eventType) {
// 这个方法分了三种情况,说明这个方法是个公共方法,紧跟着上面GenericApplicationListenerAdapter对象执行到这里,delegate就是一个ApplicationListener的普通实现类MyApplicationEventListener,会进入到else代码块中
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));
}
else {
// 即判断解析listener的泛型类型是否是事件类型以及事件类型的父类型
return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
}
}
// ① -> ④
private boolean supportsEvent(
ConfigurableBeanFactory beanFactory, String listenerBeanName, ResolvableType eventType) {
// 从容器中获取beanName对应的beanType
Class<?> listenerType = beanFactory.getType(listenerBeanName);
if (listenerType == null || GenericApplicationListener.class.isAssignableFrom(listenerType) ||
SmartApplicationListener.class.isAssignableFrom(listenerType)) {
return true;
}
// supportEvent判断listener bean的泛型类型是否是eventType类型以及eventType类型的父类型
// 举个例子就是:判断MyListener implements ApplicationListener<T>中的T类型是否是eventType类型以及eventType类型的父类型
if (!supportsEvent(listenerType, eventType)) {
return false;
}
try {
BeanDefinition bd = beanFactory.getMergedBeanDefinition(listenerBeanName);
// 这里有点不理解,上面supportsEvent已经判断了一次了,这里的逻辑和supportsEvent基本一致
// 为什么还要再来一遍?
ResolvableType genericEventType = bd.getResolvableType().as(ApplicationListener.class).getGeneric();
return (genericEventType == ResolvableType.NONE || genericEventType.isAssignableFrom(eventType));
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore - no need to check resolvable type for manually registered singleton
return true;
}
}
上面源码详细介绍了如何查找对事件感兴趣的listeners的经过,基本逻辑如下:
- 首先遍历广播器中已经注册的listeners,依次判断listeners是否对事件"感兴趣"。
- 其次遍历广播器中已经注册的ApplicationListener类型的beanName列表,依次判断beanName对应的beanType是否支持事件类型,如果支持,就获取或创建出该ApplicationListener bean,然后判断listener是否对事件"感兴趣"。
判断listener对象是否对发布的事件"感兴趣",以上面示例代码为例,MyApplicationEventListener implements ApplicationListener<MyApplicationEvent>,自定义listener直接实现了ApplicationListener接口,而非GenericApplicationListener、SmartApplicationListener类型对象,所以判断MyApplicationEventListener接口ApplicationListener上的泛型MyApplicationEvent类型是否是事件类型以及事件类型的父类型。当发布的事件类型为MyApplicationEvent时,MyApplicationEventListener自然就会被找到,处理这个事件。
找到感兴趣的listeners后,处理事件的逻辑入口在上面代码中标记为了②,这个逻辑比较简单,贴一下代码:
// 代码位置:org.springframework.context.event.SimpleApplicationEventMulticaster#invokeListener
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
// 调用listener的onApplicationEvent方法
doInvokeListener(listener, event);
}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 调用listener的onApplicationEvent方法,由此进入我们自定义的listener逻辑
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
// ...
}
}
第3、4步合起来,画一个简单的流程图,如下: