Consistent FactoryBean cache visibility in concurrent creation scenarios

Issue: SPR-16625
Issue: SPR-16627
This commit is contained in:
Juergen Hoeller
2018-03-23 17:34:33 +01:00
parent 937cd48fcb
commit 8d8e218b52
3 changed files with 42 additions and 24 deletions

View File

@@ -927,12 +927,16 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
if (bw != null) {
return (FactoryBean<?>) bw.getWrappedInstance();
}
Object beanInstance = getSingleton(beanName, false);
if (beanInstance instanceof FactoryBean) {
return (FactoryBean<?>) beanInstance;
}
if (isSingletonCurrentlyInCreation(beanName) ||
(mbd.getFactoryBeanName() != null && isSingletonCurrentlyInCreation(mbd.getFactoryBeanName()))) {
return null;
}
Object instance = null;
Object instance;
try {
// Mark this bean as currently in creation, even if just partially.
beforeSingletonCreation(beanName);
@@ -1845,8 +1849,21 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
*/
@Override
protected void removeSingleton(String beanName) {
super.removeSingleton(beanName);
this.factoryBeanInstanceCache.remove(beanName);
synchronized (getSingletonMutex()) {
super.removeSingleton(beanName);
this.factoryBeanInstanceCache.remove(beanName);
}
}
/**
* Overridden to clear FactoryBean instance cache as well.
*/
@Override
protected void clearSingletonCache() {
synchronized (getSingletonMutex()) {
super.clearSingletonCache();
this.factoryBeanInstanceCache.clear();
}
}

View File

@@ -392,11 +392,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
// No entry yet -> fully synchronized manipulation of the containedBeans Set
synchronized (this.containedBeanMap) {
containedBeans = this.containedBeanMap.get(containingBeanName);
if (containedBeans == null) {
containedBeans = new LinkedHashSet<>(8);
this.containedBeanMap.put(containingBeanName, containedBeans);
}
containedBeans = this.containedBeanMap.computeIfAbsent(containingBeanName, k -> new LinkedHashSet<>(8));
containedBeans.add(containedBeanName);
}
registerDependentBean(containedBeanName, containingBeanName);
@@ -418,19 +414,12 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
// No entry yet -> fully synchronized manipulation of the dependentBeans Set
synchronized (this.dependentBeanMap) {
dependentBeans = this.dependentBeanMap.get(canonicalName);
if (dependentBeans == null) {
dependentBeans = new LinkedHashSet<>(8);
this.dependentBeanMap.put(canonicalName, dependentBeans);
}
dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
dependentBeans.add(dependentBeanName);
}
synchronized (this.dependenciesForBeanMap) {
Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName);
if (dependenciesForBean == null) {
dependenciesForBean = new LinkedHashSet<>(8);
this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);
}
Set<String> dependenciesForBean =
this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
dependenciesForBean.add(canonicalName);
}
}
@@ -525,6 +514,14 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
this.dependentBeanMap.clear();
this.dependenciesForBeanMap.clear();
clearSingletonCache();
}
/**
* Clear all cached singleton instances in this registry.
* @since 4.3.15
*/
protected void clearSingletonCache() {
synchronized (this.singletonObjects) {
this.singletonObjects.clear();
this.singletonFactories.clear();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -214,17 +214,21 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
*/
@Override
protected void removeSingleton(String beanName) {
super.removeSingleton(beanName);
this.factoryBeanObjectCache.remove(beanName);
synchronized (getSingletonMutex()) {
super.removeSingleton(beanName);
this.factoryBeanObjectCache.remove(beanName);
}
}
/**
* Overridden to clear the FactoryBean object cache as well.
*/
@Override
public void destroySingletons() {
super.destroySingletons();
this.factoryBeanObjectCache.clear();
protected void clearSingletonCache() {
synchronized (getSingletonMutex()) {
super.clearSingletonCache();
this.factoryBeanObjectCache.clear();
}
}
/**