《spring擴展點之三:Spring 的監聽事件 ApplicationListener 和 ApplicationEvent 用法,在spring啓動後作些事情》html
《服務網關zuul之七:zuul中的動態刷新路由配置》java
《觀察者模式與監聽模式》web
《JDK自帶的觀察者模式》spring
《JDK自帶的監聽器模式》緩存
Spring中的監聽器模式框架
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * publishEvent觸發該方方法 * 能夠在該方法中寫各類業務邏輯 */ void onApplicationEvent(E event); }
public abstract class ApplicationEvent extends EventObject { /** use serialVersionUID from Spring 1.2 for interoperability */ private static final long serialVersionUID = 7099057708183571937L; /** System time when the event happened */ private final long timestamp; /** * Create a new ApplicationEvent. * @param source the object on which the event initially occurred (never {@code null}) */ public ApplicationEvent(Object source) { super(source); this.timestamp = System.currentTimeMillis(); } /** * Return the system time in milliseconds when the event happened. */ public final long getTimestamp() { return this.timestamp; } }
spring-context-4.3.14.RELEASE-sources.jar中的ApplicationListener.java類類異步
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); }
jdk中的EventListener.java類是一個空接口ide
public interface EventListener { }
spring-context-4.3.14.RELEASE-sources.jar中的ApplicationEventPublisher.java類
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 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類中publishEvent方法實現:源碼分析
protected void publishEvent(Object event, 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<Object>(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); } } }
ApplicationEventMulticaster的multicastEvent方法的實如今SimpleApplicationEventMulticaster類中:
@Override public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); //得到監聽器集合,遍歷監聽器,可支持同步和異步的廣播事件 for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(new Runnable() { @Override public void run() { invokeListener(listener, event); } }); } else { invokeListener(listener, event); } } }
invokeListener()方法:
這就執行了ApplicationListener的onApplicationEvent方法,這裏是事件發生的地方。
在Spring容器初始化的時候,也就是在AbstractApplicationContext.java在refresh()中:
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ...... try { ...... // Initialize event multicaster for this context. //初始化一個事件註冊表 initApplicationEventMulticaster(); ...... // Check for listener beans and register them. //註冊事件監聽器 registerListeners(); ...... } } }
也就是在AbstractApplicationContext.java的initApplicationEventMulticaster方法初始化事件註冊表
protected void initApplicationEventMulticaster() { //得到beanFactory ConfigurableListableBeanFactory beanFactory = getBeanFactory(); //先查找BeanFactory中是否有ApplicationEventMulticaster if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); } else {//若是BeanFactory中不存在,就建立一個SimpleApplicationEventMulticaster this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); } }
在SimpleApplicationEventMulticaster在父類AbstractApplicationEventMulticaster類中有以下屬性:
//註冊表 private final ListenerRetriever defaultRetriever = new ListenerRetriever(false); //註冊表的緩存 private final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<ListenerCacheKey, ListenerRetriever>(64); private BeanFactory beanFactory;
ListenerRetriever.java是一個內部類,主要做用:助手類,它封裝特定的目標偵聽器集合,容許對預過濾的偵聽器進行高效的檢索。此助手的實例緩存每一個事件類型和源類型。
ListenerRetriever.java的結構以下:
//用來存放監聽事件 public final Set<ApplicationListener> applicationListeners; //存放監聽事件的類名稱 public final Set<String> applicationListenerBeans; private final boolean preFiltered;
初始化註冊表以後,就會把事件註冊到註冊表中,AbstractApplicationContext.registerListeners():
protected void registerListeners() { //獲取全部的Listener,把事件的bean放到ApplicationEventMulticaster中 for (ApplicationListener<?> listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let post-processors apply to them! String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); //把事件的名稱放到ApplicationListenerBean裏去。 for (String lisName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(lisName); } }
Spring使用反射機制,經過方法getBeansOfType獲取全部繼承了ApplicationListener接口的監聽器,而後把監聽器放到註冊表中,因此咱們能夠在Spring配置文件中配置自定義監聽器,在Spring初始化的時候,會把監聽器自動註冊到註冊表中去。
applicationContext.java中的getBeansOfType(Class<T> type)的實如今
@Override @SuppressWarnings("unchecked") public <T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException { boolean isFactoryType = (type != null && FactoryBean.class.isAssignableFrom(type)); Map<String, T> matches = new LinkedHashMap<String, T>(); for (Map.Entry<String, Object> entry : this.beans.entrySet()) { String beanName = entry.getKey(); Object beanInstance = entry.getValue(); // Is bean a FactoryBean? if (beanInstance instanceof FactoryBean && !isFactoryType) { // Match object created by FactoryBean. FactoryBean<?> factory = (FactoryBean<?>) beanInstance; Class<?> objectType = factory.getObjectType(); if ((includeNonSingletons || factory.isSingleton()) && objectType != null && (type == null || type.isAssignableFrom(objectType))) { matches.put(beanName, getBean(beanName, type)); } } else { if (type == null || type.isInstance(beanInstance)) { // If type to match is FactoryBean, return FactoryBean itself. // Else, return bean instance. if (isFactoryType) { beanName = FACTORY_BEAN_PREFIX + beanName; } matches.put(beanName, (T) beanInstance); } } } return matches; }
反射的見《instanceof, isinstance,isAssignableFrom的區別》
ApplicationContext發佈事件能夠參考上面的內容。發佈事件的時候的一個方法,getApplicationListeners:
protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event) { //獲取事件類型 Class<? extends ApplicationEvent> eventType = event.getClass(); //或去事件源類型 Class sourceType = event.getSource().getClass(); ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType); //從緩存中查找ListenerRetriever ListenerRetriever retriever = this.retrieverCache.get(cacheKey); //緩存中存在,直接返回對應的Listener if (retriever != null) { return retriever.getApplicationListeners(); } else {//緩存中不存在,就獲取相應的Listener retriever = new ListenerRetriever(true); LinkedList<ApplicationListener> allListeners = new LinkedList<ApplicationListener>(); Set<ApplicationListener> listeners; Set<String> listenerBeans; synchronized (this.defaultRetriever) { listeners = new LinkedHashSet<ApplicationListener>(this.defaultRetriever.applicationListeners); listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans); } //根據事件類型,事件源類型,獲取所須要的監聽事件 for (ApplicationListener listener : listeners) { if (supportsEvent(listener, eventType, sourceType)) { retriever.applicationListeners.add(listener); allListeners.add(listener); } } if (!listenerBeans.isEmpty()) { BeanFactory beanFactory = getBeanFactory(); for (String listenerBeanName : listenerBeans) { ApplicationListener listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class); if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) { retriever.applicationListenerBeans.add(listenerBeanName); allListeners.add(listener); } } } OrderComparator.sort(allListeners); this.retrieverCache.put(cacheKey, retriever); 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 (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType)); }
這裏沒有進行實際的處理,實際處理在smartListener.supportsEventType(eventType)和smartListener.supportsSourceType(sourceType)方法中。
smartListener.supportsEventType(eventType):
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) { Class typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class); if (typeArg == null || typeArg.equals(ApplicationEvent.class)) { Class targetClass = AopUtils.getTargetClass(this.delegate); if (targetClass != this.delegate.getClass()) { typeArg = GenericTypeResolver.resolveTypeArgument(targetClass, ApplicationListener.class); } } return (typeArg == null || typeArg.isAssignableFrom(eventType)); }
該方法主要的邏輯就是根據事件類型判斷是否和監聽器參數泛型的類型是否一致。
smartListener.supportsSourceType(sourceType)方法的實現爲:
public boolean supportsSourceType(Class<?> sourceType) { return true; }
定義本身的監聽器要明確指定參數泛型,代表該監聽器支持的事件,若是不指明具體的泛型,則沒有監聽器監聽事件。