DefaultSingletonBeanRegistry avoids singletonObjects lock wherever possible for non-singleton factory performance
Also fixing setCurrentlyInCreation to use a concurrent Set and to apply to prototype beans as well. Issue: SPR-9819
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -321,8 +321,8 @@ public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, Single
|
||||
boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException;
|
||||
|
||||
/**
|
||||
* Explicitly control in-creation status of the specified bean. For
|
||||
* container internal use only.
|
||||
* Explicitly control the current in-creation status of the specified bean.
|
||||
* For container-internal use only.
|
||||
* @param beanName the name of the bean
|
||||
* @param inCreation whether the bean is currently in creation
|
||||
* @since 3.1
|
||||
|
||||
@@ -897,6 +897,22 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActuallyInCreation(String beanName) {
|
||||
return isSingletonCurrentlyInCreation(beanName) || isPrototypeCurrentlyInCreation(beanName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the specified prototype bean is currently in creation
|
||||
* (within the current thread).
|
||||
* @param beanName the name of the bean
|
||||
*/
|
||||
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
|
||||
Object curVal = this.prototypesCurrentlyInCreation.get();
|
||||
return (curVal != null &&
|
||||
(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback before prototype creation.
|
||||
* <p>The default implementation register the prototype as currently in creation.
|
||||
@@ -942,22 +958,6 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the specified prototype bean is currently in creation
|
||||
* (within the current thread).
|
||||
* @param beanName the name of the bean
|
||||
*/
|
||||
protected final boolean isPrototypeCurrentlyInCreation(String beanName) {
|
||||
Object curVal = this.prototypesCurrentlyInCreation.get();
|
||||
return (curVal != null &&
|
||||
(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
|
||||
}
|
||||
|
||||
public boolean isCurrentlyInCreation(String beanName) {
|
||||
Assert.notNull(beanName, "Bean name must not be null");
|
||||
return isSingletonCurrentlyInCreation(beanName) || isPrototypeCurrentlyInCreation(beanName);
|
||||
}
|
||||
|
||||
public void destroyBean(String beanName, Object beanInstance) {
|
||||
destroyBean(beanName, beanInstance, getMergedLocalBeanDefinition(beanName));
|
||||
}
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -94,11 +92,11 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
/** Set of registered singletons, containing the bean names in registration order */
|
||||
private final Set<String> registeredSingletons = new LinkedHashSet<String>(16);
|
||||
|
||||
/** Names of beans that are currently in creation */
|
||||
private final Set<String> singletonsCurrentlyInCreation = Collections.synchronizedSet(new HashSet<String>());
|
||||
/** Names of beans that are currently in creation (using a ConcurrentHashMap as a Set) */
|
||||
private final Map<String, Boolean> singletonsCurrentlyInCreation = new ConcurrentHashMap<String, Boolean>();
|
||||
|
||||
/** Names of beans currently excluded from in creation checks */
|
||||
private final Set<String> inCreationCheckExclusions = new HashSet<String>();
|
||||
/** Names of beans currently excluded from in creation checks (using a ConcurrentHashMap as a Set) */
|
||||
private final Map<String, Boolean> inCreationCheckExclusions = new ConcurrentHashMap<String, Boolean>();
|
||||
|
||||
/** List of suppressed Exceptions, available for associating related causes */
|
||||
private Set<Exception> suppressedExceptions;
|
||||
@@ -166,7 +164,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
}
|
||||
|
||||
public Object getSingleton(String beanName) {
|
||||
return getSingleton(beanName, isSingletonCurrentlyInCreation(beanName));
|
||||
return getSingleton(beanName, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,10 +177,10 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
*/
|
||||
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
|
||||
Object singletonObject = this.singletonObjects.get(beanName);
|
||||
if (singletonObject == null && allowEarlyReference) {
|
||||
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
|
||||
synchronized (this.singletonObjects) {
|
||||
singletonObject = this.earlySingletonObjects.get(beanName);
|
||||
if (singletonObject == null) {
|
||||
if (singletonObject == null && allowEarlyReference) {
|
||||
ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
|
||||
if (singletonFactory != null) {
|
||||
singletonObject = singletonFactory.getObject();
|
||||
@@ -289,6 +287,34 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
}
|
||||
|
||||
|
||||
public void setCurrentlyInCreation(String beanName, boolean inCreation) {
|
||||
Assert.notNull(beanName, "Bean name must not be null");
|
||||
if (!inCreation) {
|
||||
this.inCreationCheckExclusions.put(beanName, Boolean.TRUE);
|
||||
}
|
||||
else {
|
||||
this.inCreationCheckExclusions.remove(beanName);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCurrentlyInCreation(String beanName) {
|
||||
Assert.notNull(beanName, "Bean name must not be null");
|
||||
return (!this.inCreationCheckExclusions.containsKey(beanName) && isActuallyInCreation(beanName));
|
||||
}
|
||||
|
||||
protected boolean isActuallyInCreation(String beanName) {
|
||||
return isSingletonCurrentlyInCreation(beanName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the specified singleton bean is currently in creation
|
||||
* (within the entire factory).
|
||||
* @param beanName the name of the bean
|
||||
*/
|
||||
public boolean isSingletonCurrentlyInCreation(String beanName) {
|
||||
return this.singletonsCurrentlyInCreation.containsKey(beanName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback before singleton creation.
|
||||
* <p>Default implementation register the singleton as currently in creation.
|
||||
@@ -296,7 +322,8 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
* @see #isSingletonCurrentlyInCreation
|
||||
*/
|
||||
protected void beforeSingletonCreation(String beanName) {
|
||||
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
|
||||
if (!this.inCreationCheckExclusions.containsKey(beanName) &&
|
||||
this.singletonsCurrentlyInCreation.put(beanName, Boolean.TRUE) != null) {
|
||||
throw new BeanCurrentlyInCreationException(beanName);
|
||||
}
|
||||
}
|
||||
@@ -308,29 +335,12 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
||||
* @see #isSingletonCurrentlyInCreation
|
||||
*/
|
||||
protected void afterSingletonCreation(String beanName) {
|
||||
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
|
||||
if (!this.inCreationCheckExclusions.containsKey(beanName) &&
|
||||
!this.singletonsCurrentlyInCreation.remove(beanName)) {
|
||||
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
|
||||
}
|
||||
}
|
||||
|
||||
public final void setCurrentlyInCreation(String beanName, boolean inCreation) {
|
||||
if (!inCreation) {
|
||||
this.inCreationCheckExclusions.add(beanName);
|
||||
}
|
||||
else {
|
||||
this.inCreationCheckExclusions.remove(beanName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the specified singleton bean is currently in creation
|
||||
* (within the entire factory).
|
||||
* @param beanName the name of the bean
|
||||
*/
|
||||
public final boolean isSingletonCurrentlyInCreation(String beanName) {
|
||||
return this.singletonsCurrentlyInCreation.contains(beanName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the given bean to the list of disposable beans in this registry.
|
||||
|
||||
Reference in New Issue
Block a user