001/*002 * Copyright 2002-2020 the original author or authors.003 *004 * Licensed under the Apache License, Version 2.0 (the "License");005 * you may not use this file except in compliance with the License.006 * You may obtain a copy of the License at007 *008 * https://www.apache.org/licenses/LICENSE-2.0009 *010 * Unless required by applicable law or agreed to in writing, software011 * distributed under the License is distributed on an "AS IS" BASIS,012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.013 * See the License for the specific language governing permissions and014 * limitations under the License.015 */016017package org.springframework.context.event;018019import java.util.ArrayList;020import java.util.Collection;021import java.util.LinkedHashSet;022import java.util.List;023import java.util.Map;024import java.util.Set;025import java.util.concurrent.ConcurrentHashMap;026027import org.springframework.aop.framework.AopProxyUtils;028import org.springframework.beans.factory.BeanClassLoaderAware;029import org.springframework.beans.factory.BeanFactory;030import org.springframework.beans.factory.BeanFactoryAware;031import org.springframework.beans.factory.NoSuchBeanDefinitionException;032import org.springframework.beans.factory.config.BeanDefinition;033import org.springframework.beans.factory.config.ConfigurableBeanFactory;034import org.springframework.context.ApplicationEvent;035import org.springframework.context.ApplicationListener;036import org.springframework.core.ResolvableType;037import org.springframework.core.annotation.AnnotationAwareOrderComparator;038import org.springframework.lang.Nullable;039import org.springframework.util.Assert;040import org.springframework.util.ClassUtils;041import org.springframework.util.ObjectUtils;042043/**044 * Abstract implementation of the {@link ApplicationEventMulticaster} interface,045 * providing the basic listener registration facility.046 *047 * <p>Doesn't permit multiple instances of the same listener by default,048 * as it keeps listeners in a linked Set. The collection class used to hold049 * ApplicationListener objects can be overridden through the "collectionClass"050 * bean property.051 *052 * <p>Implementing ApplicationEventMulticaster's actual {@link #multicastEvent} method053 * is left to subclasses. {@link SimpleApplicationEventMulticaster} simply multicasts054 * all events to all registered listeners, invoking them in the calling thread.055 * Alternative implementations could be more sophisticated in those respects.056 *057 * @author Juergen Hoeller058 * @author Stephane Nicoll059 * @since 1.2.3060 * @see #getApplicationListeners(ApplicationEvent, ResolvableType)061 * @see SimpleApplicationEventMulticaster062 */063public abstract class AbstractApplicationEventMulticaster064 implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {065066 private final DefaultListenerRetriever defaultRetriever = new DefaultListenerRetriever();067068 final Map<ListenerCacheKey, CachedListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);069070 @Nullable071 private ClassLoader beanClassLoader;072073 @Nullable074 private ConfigurableBeanFactory beanFactory;075076077 @Override078 public void setBeanClassLoader(ClassLoader classLoader) {079 this.beanClassLoader = classLoader;080 }081082 @Override083 public void setBeanFactory(BeanFactory beanFactory) {084 if (!(beanFactory instanceof ConfigurableBeanFactory)) {085 throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory);086 }087 this.beanFactory = (ConfigurableBeanFactory) beanFactory;088 if (this.beanClassLoader == null) {089 this.beanClassLoader = this.beanFactory.getBeanClassLoader();090 }091 }092093 private ConfigurableBeanFactory getBeanFactory() {094 if (this.beanFactory == null) {095 throw new IllegalStateException("ApplicationEventMulticaster cannot retrieve listener beans " +096 "because it is not associated with a BeanFactory");097 }098 return this.beanFactory;099 }100101102 @Override103 public void addApplicationListener(ApplicationListener<?> listener) {104 synchronized (this.defaultRetriever) {105 // Explicitly remove target for a proxy, if registered already,106 // in order to avoid double invocations of the same listener.107 Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);108 if (singletonTarget instanceof ApplicationListener) {109 this.defaultRetriever.applicationListeners.remove(singletonTarget);110 }111 this.defaultRetriever.applicationListeners.add(listener);112 this.retrieverCache.clear();113 }114 }115116 @Override117 public void addApplicationListenerBean(String listenerBeanName) {118 synchronized (this.defaultRetriever) {119 this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);120 this.retrieverCache.clear();121 }122 }123124 @Override125 public void removeApplicationListener(ApplicationListener<?> listener) {126 synchronized (this.defaultRetriever) {127 this.defaultRetriever.applicationListeners.remove(listener);128 this.retrieverCache.clear();129 }130 }131132 @Override133 public void removeApplicationListenerBean(String listenerBeanName) {134 synchronized (this.defaultRetriever) {135 this.defaultRetriever.applicationListenerBeans.remove(listenerBeanName);136 this.retrieverCache.clear();137 }138 }139140 @Override141 public void removeAllListeners() {142 synchronized (this.defaultRetriever) {143 this.defaultRetriever.applicationListeners.clear();144 this.defaultRetriever.applicationListenerBeans.clear();145 this.retrieverCache.clear();146 }147 }148149150 /**151 * Return a Collection containing all ApplicationListeners.152 * @return a Collection of ApplicationListeners153 * @see org.springframework.context.ApplicationListener154 */155 protected Collection<ApplicationListener<?>> getApplicationListeners() {156 synchronized (this.defaultRetriever) {157 return this.defaultRetriever.getApplicationListeners();158 }159 }160161 /**162 * Return a Collection of ApplicationListeners matching the given163 * event type. Non-matching listeners get excluded early.164 * @param event the event to be propagated. Allows for excluding165 * non-matching listeners early, based on cached matching information.166 * @param eventType the event type167 * @return a Collection of ApplicationListeners168 * @see org.springframework.context.ApplicationListener169 */170 protected Collection<ApplicationListener<?>> getApplicationListeners(171 ApplicationEvent event, ResolvableType eventType) {172173 Object source = event.getSource();174 Class<?> sourceType = (source != null ? source.getClass() : null);175 ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);176177 // Potential new retriever to populate178 CachedListenerRetriever newRetriever = null;179180 // Quick check for existing entry on ConcurrentHashMap181 CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);182 if (existingRetriever == null) {183 // Caching a new ListenerRetriever if possible184 if (this.beanClassLoader == null ||185 (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&186 (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {187 newRetriever = new CachedListenerRetriever();188 existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);189 if (existingRetriever != null) {190 newRetriever = null; // no need to populate it in retrieveApplicationListeners191 }192 }193 }194195 if (existingRetriever != null) {196 Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();197 if (result != null) {198 return result;199 }200 // If result is null, the existing retriever is not fully populated yet by another thread.201 // Proceed like caching wasn't possible for this current local attempt.202 }203204 return retrieveApplicationListeners(eventType, sourceType, newRetriever);205 }206207 /**208 * Actually retrieve the application listeners for the given event and source type.209 * @param eventType the event type210 * @param sourceType the event source type211 * @param retriever the ListenerRetriever, if supposed to populate one (for caching purposes)212 * @return the pre-filtered list of application listeners for the given event and source type213 */214 private Collection<ApplicationListener<?>> retrieveApplicationListeners(215 ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) {216217 List<ApplicationListener<?>> allListeners = new ArrayList<>();218 Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);219 Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);220221 Set<ApplicationListener<?>> listeners;222 Set<String> listenerBeans;223