发布订阅模式之Spring源码ApplicationListener解析
-
在之前的博客中有介绍过发布订阅模式, 也就是观察者模式, 想要了解的同学可以看我博客https://editor.csdn.net/md/?articleId=126689739
-
他的uml图如下(图一)
-
这里我们在重点讲一下发布订阅模式在spring源码中的应用
-
为了大家有一个整体的认识, 我先把主要涉及到的类先画出uml, 如下
-
接下来我们来分析一下源码
-
ApplicationListener作为观察者, 定义onApplicationEvent。 对应图一的Observer
-
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); }
-
-
事件的发布, 是通过ApplicationContext 的publishEvent , 他的默认实现是接口ApplicationEventPublisher, 所以 ApplicationContext 就作为观察目标(图一的Subject)
-
public interface ApplicationEventPublisher { /** * Notify all <strong>matching</strong> listeners registered with this * application of an application event. Events may be framework events * (such as RequestHandledEvent) or application-specific events. * @param event the event to publish * @see org.springframework.web.context.support.RequestHandledEvent */ default void publishEvent(ApplicationEvent event) { publishEvent((Object) event); } /** * Notify all <strong>matching</strong> listeners registered with this * application of an event. * <p>If the specified {@code event} is not an {@link ApplicationEvent}, * it is wrapped in a {@link PayloadApplicationEvent}. * @param event the event to publish * @since 4.2 * @see PayloadApplicationEvent */ void publishEvent(Object event); }
-
-
我们再看一下实现细节, 可以找到AbstractApplicationContext, 代码片段如下
-
protected void publishEvent(Object event, @Nullable ResolvableType eventType) { Assert.notNull(event, "Event must not be null"); if (logger.isTraceEnabled()) { logger.trace("Publishing event in " + getDisplayName() + ": " + event); } // Decorate event as an ApplicationEvent if necessary ApplicationEvent applicationEvent; if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent) event; } else { applicationEvent = new PayloadApplicationEvent<>(this, event); if (eventType == null) { eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType(); } } // 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); } // Publish event via parent context as well... if (this.parent != null) { if (this.parent instanceof AbstractApplicationContext) { ((AbstractApplicationContext) this.parent).publishEvent(event, eventType); } else { this.parent.publishEvent(event); } } }
-
重点看 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);这是他的具体实现, 可以定位到org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent, 代码如下, 也是用for循环去便利观察者, 参考图一中的for
-
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(() -> invokeListener(listener, event)); } else { invokeListener(listener, event); } } }
-
最后我们看一下invokeListener的实现, doInvokeListener, 可以发现, 是调用了观察者ApplicationListener的onApplicationEvent方法
-
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.isDebugEnabled()) { logger.debug("Non-matching event type for listener: " + listener, ex); } } else { throw ex; } } }
-
-
-
到这里你是不是已近明白了尼
-