Avoid duplicate application listeners (proxy vs. proxy target)

In AbstractApplicationEventMulticaster.retrieveApplicationListeners,
despite best efforts to avoid it, unwrapped proxies (singleton targets)
can end up in the list of programmatically registered listeners. In
order to avoid duplicates, we need to find and replace them by their
proxy counterparts, because if both a proxy and its target end up in
'allListeners', listeners will fire twice.

Fixes #28283.
This commit is contained in:
Alexander Kriegisch
2022-04-11 14:51:04 +07:00
committed by Juergen Hoeller
parent 86d52a677a
commit 20c688e68d

View File

@@ -263,6 +263,24 @@ public abstract class AbstractApplicationEventMulticaster
if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
// Despite best efforts to avoid it, unwrapped proxies (singleton targets) can end up in the
// list of programmatically registered listeners. In order to avoid duplicates, we need to find
// and replace them by their proxy counterparts, because if both a proxy and its target end up
// in 'allListeners', listeners will fire twice.
ApplicationListener<?> unwrappedListener =
(ApplicationListener<?>) AopProxyUtils.getSingletonTarget(listener);
if (listener != unwrappedListener) {
if (filteredListeners != null && filteredListeners.contains(unwrappedListener)) {
filteredListeners.remove(unwrappedListener);
filteredListeners.add(listener);
}
if (allListeners.contains(unwrappedListener)) {
allListeners.remove(unwrappedListener);
allListeners.add(listener);
}
}
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
if (beanFactory.isSingleton(listenerBeanName)) {