Skip to content

Commit 52124fa

Browse files
committed
Avoid wide locks in order to remove deadlock potential in case of multi-threaded singleton creation/destruction
Issue: SPR-10020 Issue: SPR-8471
1 parent 87b7e3d commit 52124fa

File tree

3 files changed

+55
-49
lines changed

3 files changed

+55
-49
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -576,35 +576,36 @@ public void preInstantiateSingletons() throws BeansException {
576576
if (this.logger.isInfoEnabled()) {
577577
this.logger.info("Pre-instantiating singletons in " + this);
578578
}
579+
List<String> beanNames;
579580
synchronized (this.beanDefinitionMap) {
580581
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
581582
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
582-
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
583-
for (String beanName : beanNames) {
584-
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
585-
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
586-
if (isFactoryBean(beanName)) {
587-
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
588-
boolean isEagerInit;
589-
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
590-
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
591-
public Boolean run() {
592-
return ((SmartFactoryBean<?>) factory).isEagerInit();
593-
}
594-
}, getAccessControlContext());
595-
}
596-
else {
597-
isEagerInit = (factory instanceof SmartFactoryBean &&
598-
((SmartFactoryBean<?>) factory).isEagerInit());
599-
}
600-
if (isEagerInit) {
601-
getBean(beanName);
602-
}
583+
beanNames = new ArrayList<String>(this.beanDefinitionNames);
584+
}
585+
for (String beanName : beanNames) {
586+
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
587+
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
588+
if (isFactoryBean(beanName)) {
589+
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
590+
boolean isEagerInit;
591+
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
592+
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
593+
public Boolean run() {
594+
return ((SmartFactoryBean<?>) factory).isEagerInit();
595+
}
596+
}, getAccessControlContext());
603597
}
604598
else {
599+
isEagerInit = (factory instanceof SmartFactoryBean &&
600+
((SmartFactoryBean<?>) factory).isEagerInit());
601+
}
602+
if (isEagerInit) {
605603
getBean(beanName);
606604
}
607605
}
606+
else {
607+
getBean(beanName);
608+
}
608609
}
609610
}
610611
}
@@ -650,9 +651,9 @@ public void registerBeanDefinition(String beanName, BeanDefinition beanDefinitio
650651
this.frozenBeanDefinitionNames = null;
651652
}
652653
this.beanDefinitionMap.put(beanName, beanDefinition);
653-
654-
resetBeanDefinition(beanName);
655654
}
655+
656+
resetBeanDefinition(beanName);
656657
}
657658

658659
public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
@@ -668,9 +669,9 @@ public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionExc
668669
}
669670
this.beanDefinitionNames.remove(beanName);
670671
this.frozenBeanDefinitionNames = null;
671-
672-
resetBeanDefinition(beanName);
673672
}
673+
674+
resetBeanDefinition(beanName);
674675
}
675676

676677
/**
@@ -685,9 +686,7 @@ protected void resetBeanDefinition(String beanName) {
685686
// Remove corresponding bean from singleton cache, if any. Shouldn't usually
686687
// be necessary, rather just meant for overriding a context's default beans
687688
// (e.g. the default StaticMessageSource in a StaticApplicationContext).
688-
synchronized (getSingletonMutex()) {
689-
destroySingleton(beanName);
690-
}
689+
destroySingleton(beanName);
691690

692691
// Remove any assumptions about by-type mappings
693692
this.singletonBeanNamesByType.clear();

spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -447,11 +447,12 @@ public void destroySingletons() {
447447
this.singletonsCurrentlyInDestruction = true;
448448
}
449449

450+
String[] disposableBeanNames;
450451
synchronized (this.disposableBeans) {
451-
String[] disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
452-
for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
453-
destroySingleton(disposableBeanNames[i]);
454-
}
452+
disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
453+
}
454+
for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
455+
destroySingleton(disposableBeanNames[i]);
455456
}
456457

457458
this.containedBeanMap.clear();

spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2010 the original author or authors.
2+
* Copyright 2002-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -113,7 +113,9 @@ private BeanFactory getBeanFactory() {
113113
* @see org.springframework.context.ApplicationListener
114114
*/
115115
protected Collection<ApplicationListener> getApplicationListeners() {
116-
return this.defaultRetriever.getApplicationListeners();
116+
synchronized (this.defaultRetriever) {
117+
return this.defaultRetriever.getApplicationListeners();
118+
}
117119
}
118120

119121
/**
@@ -135,26 +137,30 @@ protected Collection<ApplicationListener> getApplicationListeners(ApplicationEve
135137
else {
136138
retriever = new ListenerRetriever(true);
137139
LinkedList<ApplicationListener> allListeners = new LinkedList<ApplicationListener>();
140+
Set<ApplicationListener> listeners;
141+
Set<String> listenerBeans;
138142
synchronized (this.defaultRetriever) {
139-
for (ApplicationListener listener : this.defaultRetriever.applicationListeners) {
140-
if (supportsEvent(listener, eventType, sourceType)) {
141-
retriever.applicationListeners.add(listener);
142-
allListeners.add(listener);
143-
}
143+
listeners = new LinkedHashSet<ApplicationListener>(this.defaultRetriever.applicationListeners);
144+
listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
145+
}
146+
for (ApplicationListener listener : listeners) {
147+
if (supportsEvent(listener, eventType, sourceType)) {
148+
retriever.applicationListeners.add(listener);
149+
allListeners.add(listener);
144150
}
145-
if (!this.defaultRetriever.applicationListenerBeans.isEmpty()) {
146-
BeanFactory beanFactory = getBeanFactory();
147-
for (String listenerBeanName : this.defaultRetriever.applicationListenerBeans) {
148-
ApplicationListener listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
149-
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
150-
retriever.applicationListenerBeans.add(listenerBeanName);
151-
allListeners.add(listener);
152-
}
151+
}
152+
if (!listenerBeans.isEmpty()) {
153+
BeanFactory beanFactory = getBeanFactory();
154+
for (String listenerBeanName : listenerBeans) {
155+
ApplicationListener listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
156+
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
157+
retriever.applicationListenerBeans.add(listenerBeanName);
158+
allListeners.add(listener);
153159
}
154160
}
155-
OrderComparator.sort(allListeners);
156-
this.retrieverCache.put(cacheKey, retriever);
157161
}
162+
OrderComparator.sort(allListeners);
163+
this.retrieverCache.put(cacheKey, retriever);
158164
return allListeners;
159165
}
160166
}

0 commit comments

Comments
 (0)