Skip to content

Commit 59189e5

Browse files
committed
Backported core container concurrency refinements
Issue: SPR-16620 Issue: SPR-16625 Issue: SPR-16627
1 parent 65a8aa1 commit 59189e5

File tree

4 files changed

+68
-39
lines changed

4 files changed

+68
-39
lines changed

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

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 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.
@@ -908,12 +908,16 @@ private FactoryBean<?> getSingletonFactoryBeanForTypeCheck(String beanName, Root
908908
if (bw != null) {
909909
return (FactoryBean<?>) bw.getWrappedInstance();
910910
}
911+
Object beanInstance = getSingleton(beanName, false);
912+
if (beanInstance instanceof FactoryBean) {
913+
return (FactoryBean<?>) beanInstance;
914+
}
911915
if (isSingletonCurrentlyInCreation(beanName) ||
912916
(mbd.getFactoryBeanName() != null && isSingletonCurrentlyInCreation(mbd.getFactoryBeanName()))) {
913917
return null;
914918
}
915919

916-
Object instance = null;
920+
Object instance;
917921
try {
918922
// Mark this bean as currently in creation, even if just partially.
919923
beforeSingletonCreation(beanName);
@@ -1484,15 +1488,13 @@ protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrap
14841488
return;
14851489
}
14861490

1491+
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
1492+
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
1493+
}
1494+
14871495
MutablePropertyValues mpvs = null;
14881496
List<PropertyValue> original;
14891497

1490-
if (System.getSecurityManager() != null) {
1491-
if (bw instanceof BeanWrapperImpl) {
1492-
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
1493-
}
1494-
}
1495-
14961498
if (pvs instanceof MutablePropertyValues) {
14971499
mpvs = (MutablePropertyValues) pvs;
14981500
if (mpvs.isConverted()) {
@@ -1628,7 +1630,6 @@ public Object run() {
16281630
(mbd != null ? mbd.getResourceDescription() : null),
16291631
beanName, "Invocation of init method failed", ex);
16301632
}
1631-
16321633
if (mbd == null || !mbd.isSynthetic()) {
16331634
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
16341635
}
@@ -1780,8 +1781,21 @@ protected Object postProcessObjectFromFactoryBean(Object object, String beanName
17801781
*/
17811782
@Override
17821783
protected void removeSingleton(String beanName) {
1783-
super.removeSingleton(beanName);
1784-
this.factoryBeanInstanceCache.remove(beanName);
1784+
synchronized (getSingletonMutex()) {
1785+
super.removeSingleton(beanName);
1786+
this.factoryBeanInstanceCache.remove(beanName);
1787+
}
1788+
}
1789+
1790+
/**
1791+
* Overridden to clear FactoryBean instance cache as well.
1792+
*/
1793+
@Override
1794+
protected void clearSingletonCache() {
1795+
synchronized (getSingletonMutex()) {
1796+
super.clearSingletonCache();
1797+
this.factoryBeanInstanceCache.clear();
1798+
}
17851799
}
17861800

17871801

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

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -386,15 +386,8 @@ public void registerDisposableBean(String beanName, DisposableBean bean) {
386386
* @see #registerDependentBean
387387
*/
388388
public void registerContainedBean(String containedBeanName, String containingBeanName) {
389-
// A quick check for an existing entry upfront, avoiding synchronization...
390-
Set<String> containedBeans = this.containedBeanMap.get(containingBeanName);
391-
if (containedBeans != null && containedBeans.contains(containedBeanName)) {
392-
return;
393-
}
394-
395-
// No entry yet -> fully synchronized manipulation of the containedBeans Set
396389
synchronized (this.containedBeanMap) {
397-
containedBeans = this.containedBeanMap.get(containingBeanName);
390+
Set<String> containedBeans = this.containedBeanMap.get(containingBeanName);
398391
if (containedBeans == null) {
399392
containedBeans = new LinkedHashSet<String>(8);
400393
this.containedBeanMap.put(containingBeanName, containedBeans);
@@ -411,16 +404,10 @@ public void registerContainedBean(String containedBeanName, String containingBea
411404
* @param dependentBeanName the name of the dependent bean
412405
*/
413406
public void registerDependentBean(String beanName, String dependentBeanName) {
414-
// A quick check for an existing entry upfront, avoiding synchronization...
415407
String canonicalName = canonicalName(beanName);
416-
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
417-
if (dependentBeans != null && dependentBeans.contains(dependentBeanName)) {
418-
return;
419-
}
420408

421-
// No entry yet -> fully synchronized manipulation of the dependentBeans Set
422409
synchronized (this.dependentBeanMap) {
423-
dependentBeans = this.dependentBeanMap.get(canonicalName);
410+
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
424411
if (dependentBeans == null) {
425412
dependentBeans = new LinkedHashSet<String>(8);
426413
this.dependentBeanMap.put(canonicalName, dependentBeans);
@@ -445,7 +432,9 @@ public void registerDependentBean(String beanName, String dependentBeanName) {
445432
* @since 4.0
446433
*/
447434
protected boolean isDependent(String beanName, String dependentBeanName) {
448-
return isDependent(beanName, dependentBeanName, null);
435+
synchronized (this.dependentBeanMap) {
436+
return isDependent(beanName, dependentBeanName, null);
437+
}
449438
}
450439

451440
private boolean isDependent(String beanName, String dependentBeanName, Set<String> alreadySeen) {
@@ -490,7 +479,9 @@ public String[] getDependentBeans(String beanName) {
490479
if (dependentBeans == null) {
491480
return new String[0];
492481
}
493-
return StringUtils.toStringArray(dependentBeans);
482+
synchronized (this.dependentBeanMap) {
483+
return StringUtils.toStringArray(dependentBeans);
484+
}
494485
}
495486

496487
/**
@@ -504,7 +495,9 @@ public String[] getDependenciesForBean(String beanName) {
504495
if (dependenciesForBean == null) {
505496
return new String[0];
506497
}
507-
return StringUtils.toStringArray(dependenciesForBean);
498+
synchronized (this.dependenciesForBeanMap) {
499+
return StringUtils.toStringArray(dependenciesForBean);
500+
}
508501
}
509502

510503
public void destroySingletons() {
@@ -527,6 +520,14 @@ public void destroySingletons() {
527520
this.dependentBeanMap.clear();
528521
this.dependenciesForBeanMap.clear();
529522

523+
clearSingletonCache();
524+
}
525+
526+
/**
527+
* Clear all cached singleton instances in this registry.
528+
* @since 4.3.15
529+
*/
530+
protected void clearSingletonCache() {
530531
synchronized (this.singletonObjects) {
531532
this.singletonObjects.clear();
532533
this.singletonFactories.clear();
@@ -562,7 +563,11 @@ public void destroySingleton(String beanName) {
562563
*/
563564
protected void destroyBean(String beanName, DisposableBean bean) {
564565
// Trigger destruction of dependent beans first...
565-
Set<String> dependencies = this.dependentBeanMap.remove(beanName);
566+
Set<String> dependencies;
567+
synchronized (this.dependentBeanMap) {
568+
// Within full synchronization in order to guarantee a disconnected Set
569+
dependencies = this.dependentBeanMap.remove(beanName);
570+
}
566571
if (dependencies != null) {
567572
if (logger.isDebugEnabled()) {
568573
logger.debug("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);
@@ -583,7 +588,11 @@ protected void destroyBean(String beanName, DisposableBean bean) {
583588
}
584589

585590
// Trigger destruction of contained beans...
586-
Set<String> containedBeans = this.containedBeanMap.remove(beanName);
591+
Set<String> containedBeans;
592+
synchronized (this.containedBeanMap) {
593+
// Within full synchronization in order to guarantee a disconnected Set
594+
containedBeans = this.containedBeanMap.remove(beanName);
595+
}
587596
if (containedBeans != null) {
588597
for (String containedBeanName : containedBeans) {
589598
destroySingleton(containedBeanName);

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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 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.
@@ -117,7 +117,9 @@ protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanNam
117117
"Post-processing of FactoryBean's singleton object failed", ex);
118118
}
119119
}
120-
this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
120+
if (containsSingleton(beanName)) {
121+
this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
122+
}
121123
}
122124
}
123125
return (object != NULL_OBJECT ? object : null);
@@ -218,17 +220,21 @@ protected FactoryBean<?> getFactoryBean(String beanName, Object beanInstance) th
218220
*/
219221
@Override
220222
protected void removeSingleton(String beanName) {
221-
super.removeSingleton(beanName);
222-
this.factoryBeanObjectCache.remove(beanName);
223+
synchronized (getSingletonMutex()) {
224+
super.removeSingleton(beanName);
225+
this.factoryBeanObjectCache.remove(beanName);
226+
}
223227
}
224228

225229
/**
226230
* Overridden to clear the FactoryBean object cache as well.
227231
*/
228232
@Override
229-
public void destroySingletons() {
230-
super.destroySingletons();
231-
this.factoryBeanObjectCache.clear();
233+
protected void clearSingletonCache() {
234+
synchronized (getSingletonMutex()) {
235+
super.clearSingletonCache();
236+
this.factoryBeanObjectCache.clear();
237+
}
232238
}
233239

234240
/**

spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ private void startBeans(boolean autoStartupOnly) {
159159
*/
160160
private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {
161161
Lifecycle bean = lifecycleBeans.remove(beanName);
162-
if (bean != null && !this.equals(bean)) {
162+
if (bean != null && bean != this) {
163163
String[] dependenciesForBean = this.beanFactory.getDependenciesForBean(beanName);
164164
for (String dependency : dependenciesForBean) {
165165
doStart(lifecycleBeans, dependency, autoStartupOnly);

0 commit comments

Comments
 (0)