spring在容器中使用了觀察者模式:
一、spring事件:ApplicationEvent,該抽象類繼承了EventObject類,jdk建議所有的事件都應該繼承自EventObject。
二、spring事件監聽器:ApplicationLisener,該接口繼承了EventListener接口,jdk建議所有的事件監聽器都應該繼承EventListener。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); }
三、spring事件發布:ApplicationEventPublisher 。 ApplicationContext繼承了該接口,在ApplicationContext的抽象類AbstractApplicationContext中做了實現。
package org.springframework.context; 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
*/
void publishEvent(ApplicationEvent var1); void publishEvent(Object var1); }
AbstractApplicationContext類中publishEvent方法實現:
/** * Publish the given event to all listeners. * <p>Note: Listeners get initialized after the MessageSource, to be able * to access it within listener implementations. Thus, MessageSource * implementations cannot publish events. * @param event the event to publish (may be an {@link ApplicationEvent} * or a payload object to be turned into a {@link PayloadApplicationEvent}) */ @Override public void publishEvent(Object event) { publishEvent(event, null); } /** * Publish the given event to all listeners. * @param event the event to publish (may be an {@link ApplicationEvent} * or a payload object to be turned into a {@link PayloadApplicationEvent}) * @param eventType the resolved event type, if known * @since 4.2 */ 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 {
//事件廣播委托給ApplicationEventMulticaster來進行 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); } } }
由上代碼可知,AbstractApplicationContext類並沒有具體的做事件廣播,而是委托給ApplicationEventMulticaster來進行,ApplicationEventMulticaster的multicastEvent()方法實現如下:
@Override 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); } } }
protected void invokeListener(ApplicationListener listener, ApplicationEvent event) { ErrorHandler errorHandler = this.getErrorHandler(); if (errorHandler != null) { try { listener.onApplicationEvent(event); } catch (Throwable var6) { errorHandler.handleError(var6); } } else { try { listener.onApplicationEvent(event); } catch (ClassCastException var5) { LogFactory.getLog(this.getClass()).debug("Non-matching event type for listener: " + listener, var5); } } }
獲得listener集合,遍歷listener觸發事件Executor接口有多個實現類,可以支持同步或異步廣播事件。
問題:spring容器是怎么根據事件去找到事件對應的事件監聽器呢?
一、入口
private ApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:/spring/applicationContext.xml");
二、生成Spring上下文ApplicationContext
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); this.setConfigLocations(configLocations); if (refresh) { this.refresh(); } }
三、調用spring容器初始化方法
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); //初始化一個事件注冊表 // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // 初始化事件監聽器 // Check for listener beans and register them. registerListeners(); // 實例化所有單例對象,其中包括默認注冊表 // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // 發布事件 // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
3.1 initApplicationEventMulticaster()方法代碼
protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = this.getBeanFactory(); //先查找BeanFactory配置文件中是否有ApplicationEventMulticaster if (beanFactory.containsLocalBean("applicationEventMulticaster")) { this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class); if (this.logger.isDebugEnabled()) { this.logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); } } else {// 如果beanFactory中沒有,則創建一個SimpleApplicationEventMulticaster this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster); if (this.logger.isDebugEnabled()) { this.logger.debug("Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [" + this.applicationEventMulticaster + "]"); } } }
spring先從beanFactory中獲取ApplicationEventMulticaster,如果沒有自定義,則創建一個SimpleApplicationEventMulticaster。
ApplicationEventMulticaster包含以下屬性:defaultRetriever即為注冊表,注冊監聽事件的相關消息; retrieverCache用來做defaultRetriever的緩存。
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware { private final AbstractApplicationEventMulticaster.ListenerRetriever defaultRetriever = new AbstractApplicationEventMulticaster.ListenerRetriever(false); final Map<AbstractApplicationEventMulticaster.ListenerCacheKey, AbstractApplicationEventMulticaster.ListenerRetriever> retrieverCache = new ConcurrentHashMap(64); private ClassLoader beanClassLoader; private BeanFactory beanFactory; private Object retrievalMutex; }
ListenerRetriever的數據結構如下:applicationListeners用來存放監聽事件, applicationListenerBeans為存放監聽事件的類名稱。
private class ListenerRetriever { public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet(); public final Set<String> applicationListenerBeans = new LinkedHashSet(); private final boolean preFiltered;
ListenerCacheKey的數據結構如下:eventType是事件類型,sourceType是事件的源類型,即為事件的構造函數的參數類型。
private static class ListenerCacheKey { private final ResolvableType eventType; private final Class<?> sourceType;
3.2 registerListeners()方法代碼
初始化注冊表以后,則把事件注冊到注冊表中,registerListeners()
protected void registerListeners() { //獲取所有的listener的迭代器 Iterator var1 = this.getApplicationListeners().iterator(); while(var1.hasNext()) { ApplicationListener<?> listener = (ApplicationListener)var1.next(); //把獲取所有的listener, 把事件的bean放到ApplicationEventMulticaster中的ApplicationListener this.getApplicationEventMulticaster().addApplicationListener(listener); } String[] listenerBeanNames = this.getBeanNamesForType(ApplicationListener.class, true, false); String[] var7 = listenerBeanNames; int var3 = listenerBeanNames.length; for(int var4 = 0; var4 < var3; ++var4) { String listenerBeanName = var7[var4]; //把事件的名稱放到ApplicationListenerBean里去
this.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (earlyEventsToProcess != null) { Iterator var9 = earlyEventsToProcess.iterator(); while(var9.hasNext()) { ApplicationEvent earlyEvent = (ApplicationEvent)var9.next(); this.getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }
3.3 finishBeanFactoryInitialization(beanFactory)
具體會執行到下面的方法,會把AbstractApplicationEventMulticaster的defaultRetriever屬性賦值。
執行PostProcessorRegistrationDelegate類的postProcessAfterInitialization()方法:
public Object postProcessAfterInitialization(Object bean, String beanName) { if (this.applicationContext != null && bean instanceof ApplicationListener) { Boolean flag = (Boolean)this.singletonNames.get(beanName); if (Boolean.TRUE.equals(flag)) { this.applicationContext.addApplicationListener((ApplicationListener)bean); } else if (flag == null) { if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) { logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " + "but is not reachable for event multicasting by its containing ApplicationContext " + "because it does not have singleton scope. Only top-level listener beans are allowed " + "to be of non-singleton scope."); } this.singletonNames.put(beanName, Boolean.FALSE); } } return bean; }
執行AbstractApplicationContext類的addApplicationListener()方法:
public void addApplicationListener(ApplicationListener<?> listener) { if (this.applicationEventMulticaster != null) { this.applicationEventMulticaster.addApplicationListener(listener); } else { this.applicationListeners.add(listener); } }
執行AbstractApplicationEventMulticaster類的addApplicationListener()方法
public void addApplicationListener(ApplicationListener<?> listener) { Object var2 = this.retrievalMutex; synchronized(this.retrievalMutex) { this.defaultRetriever.applicationListeners.add(listener); this.retrieverCache.clear(); } }
【spring根據反射機制,通過方法getBeansOfType()獲取所有繼承了ApplicationListener接口的監聽器,然后把監聽器全放到注冊表里,所以我們可以在spring配置文件中配置自定義的監聽器,在spring初始化的時候會把監聽器自動注冊到注冊表中。】
3.4 finishRefresh()
里面執行發布事件。
protected void finishRefresh() { this.initLifecycleProcessor(); this.getLifecycleProcessor().onRefresh(); this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this))); LiveBeansView.registerApplicationContext(this); }
在applicationContext發布事件的時候。
public void publishEvent(ApplicationEvent event) { this.publishEvent(event, (ResolvableType)null); } public void publishEvent(Object event) { this.publishEvent(event, (ResolvableType)null); } protected void publishEvent(Object event, ResolvableType eventType) { Assert.notNull(event, "Event must not be null"); if (this.logger.isTraceEnabled()) { this.logger.trace("Publishing event in " + this.getDisplayName() + ": " + event); } Object applicationEvent; if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent)event; } else { applicationEvent = new PayloadApplicationEvent(this, event); if (eventType == null) { eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType(); } } if (this.earlyApplicationEvents != null) { this.earlyApplicationEvents.add(applicationEvent); } else { // 調用ApplicationEventMulticaster的multicastEvent()方法
this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType); } if (this.parent != null) { if (this.parent instanceof AbstractApplicationContext) { ((AbstractApplicationContext)this.parent).publishEvent(event, eventType); } else { this.parent.publishEvent(event); } } }
AbstractApplicationContext類並沒有具體的做事件廣播,而是委托給ApplicationEventMulticaster來進行。
ApplicationEventMulticaster的方法multicastEvent()為:public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) { ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event); Iterator var4 = this.getApplicationListeners(event, type).iterator(); while(var4.hasNext()) { final ApplicationListener<?> listener = (ApplicationListener)var4.next(); Executor executor = this.getTaskExecutor(); if (executor != null) { executor.execute(new Runnable() { public void run() { SimpleApplicationEventMulticaster.this.invokeListener(listener, event); } }); } else { this.invokeListener(listener, event); } } }
根據事件和類型獲取所有的監聽器方法: getApplicationListeners()
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) { Object source = event.getSource(); Class<?> sourceType = source != null ? source.getClass() : null; AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType); AbstractApplicationEventMulticaster.ListenerRetriever retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey);
//從緩存里查找ListenerRetriever if (retriever != null) { return retriever.getApplicationListeners(); } else if (this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader))) { Object var7 = this.retrievalMutex; synchronized(this.retrievalMutex) { retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey); if (retriever != null) { return retriever.getApplicationListeners(); } else {
//如果緩存里不存在,則去獲得 retriever = new AbstractApplicationEventMulticaster.ListenerRetriever(true); Collection<ApplicationListener<?>> listeners = this.retrieveApplicationListeners(eventType, sourceType, retriever); this.retrieverCache.put(cacheKey, retriever); return listeners; } } } else { return this.retrieveApplicationListeners(eventType, sourceType, (AbstractApplicationEventMulticaster.ListenerRetriever)null); } }
private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, Class<?> sourceType, AbstractApplicationEventMulticaster.ListenerRetriever retriever) { LinkedList<ApplicationListener<?>> allListeners = new LinkedList(); Object var7 = this.retrievalMutex; LinkedHashSet listeners; LinkedHashSet listenerBeans; synchronized(this.retrievalMutex) {
//獲取注冊表里所有的listener, defaultRetriever在前面已被賦值 listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners); listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans); } Iterator var14 = listeners.iterator(); while(var14.hasNext()) { ApplicationListener<?> listener = (ApplicationListener)var14.next();
//根據事件類型,事件源類型,獲取所需要的監聽事件 if (this.supportsEvent(listener, eventType, sourceType)) { if (retriever != null) { retriever.applicationListeners.add(listener); } allListeners.add(listener); } } if (!listenerBeans.isEmpty()) { BeanFactory beanFactory = this.getBeanFactory(); Iterator var16 = listenerBeans.iterator(); while(var16.hasNext()) { String listenerBeanName = (String)var16.next(); try { Class<?> listenerType = beanFactory.getType(listenerBeanName); if (listenerType == null || this.supportsEvent(listenerType, eventType)) { ApplicationListener<?> listener = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class); if (!allListeners.contains(listener) && this.supportsEvent(listener, eventType, sourceType)) { if (retriever != null) { retriever.applicationListenerBeans.add(listenerBeanName); } allListeners.add(listener); } } } catch (NoSuchBeanDefinitionException var13) { ; } } } AnnotationAwareOrderComparator.sort(allListeners); return allListeners; }
配合上面的注解,即可理解,根據事件和事件類型找到對應的監聽器,那么如何根據事件類型找到對應的監聽器呢?
上面方法中的supportsEvent(listener, eventType, sourceType)方法實現了根據事件類型查找對應的監聽器,代碼具體實現為:
protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, Class<?> sourceType) { GenericApplicationListener smartListener = listener instanceof GenericApplicationListener ? (GenericApplicationListener)listener : new GenericApplicationListenerAdapter(listener); return ((GenericApplicationListener)smartListener).supportsEventType(eventType) && ((GenericApplicationListener)smartListener).supportsSourceType(sourceType); }
如上可知:上面方法的返回結果跟方法smartListener.supportsEventType(eventType)和smartListener.supportsSourceType(sourceType)有關。
smartListener.supportsEventType(eventType)方法實現為:
public boolean supportsEventType(ResolvableType eventType) { if (this.delegate instanceof SmartApplicationListener) { Class<? extends ApplicationEvent> eventClass = eventType.getRawClass(); return ((SmartApplicationListener)this.delegate).supportsEventType(eventClass); } else { return this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType); } }
該方法主要的邏輯就是根據事件類型判斷是否和監聽器參數泛型的類型是否一致。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); }
在定義自己的監聽器要明確指定參數泛型,表明該監聽器支持的事件,如果不指明具體的泛型,則沒有監聽器監聽事件。
smartListener.supportsSourceType(sourceType)方法的實現為:
public boolean supportsSourceType(Class<?> sourceType) { return this.delegate instanceof SmartApplicationListener ? ((SmartApplicationListener)this.delegate).supportsSourceType(sourceType) : true; }
以上是spring的事件體系。
四、自定義事件和監聽器
我們可以使用spring的事件廣播體系,自定義自己的事件:
自定義事件,繼承ApplicationEvent:
public class DIYEvent extends ApplicationEvent { private static final long serialVersionUID = 7099057708183571977L; public DIYEvent(String source) { super(source); } }
自定義listener,繼承ApplicationListener
@Component public class DIYListener implements ApplicationListener<DIYEvent> { @Override public void onApplicationEvent(DIYEvent diyEvent) { System.out.println("自定義監聽器執行"); System.out.println(diyEvent.getSource()); } }
測試觸發事件:
public class DIYTest{ private ApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:/spring/applicationContext.xml"); @Test public void diyTest(){ applicationContext.publishEvent(new DIYEvent("測試數據")); } }
獲取ApplicationContext,發布事件。
調試結果:
自定義監聽器執行
測試數據