Permalink
Browse files

DefaultSingletonBeanRegistry avoids singletonObjects lock wherever po…

…ssible for non-singleton factory performance

Also fixing setCurrentlyInCreation to use a concurrent Set and to apply to prototype beans as well.

Issue: SPR-9819
  • Loading branch information...
1 parent de91d75 commit f6209cd7af800a74151ce0377b9206246d38691b @jhoeller jhoeller committed Nov 8, 2012
@@ -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 @@
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 @@ else if (containsSingleton(beanName)) {
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 @@ else if (curVal instanceof Set) {
}
}
- /**
- * 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 @@
/** 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 @@ protected void addSingletonFactory(String beanName, ObjectFactory singletonFacto
}
public Object getSingleton(String beanName) {
- return getSingleton(beanName, isSingletonCurrentlyInCreation(beanName));
+ return getSingleton(beanName, true);
@philwebb

philwebb Jun 23, 2013

Owner

SPR-10674

}
/**
@@ -179,10 +177,10 @@ public Object getSingleton(String beanName) {
*/
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,14 +287,43 @@ public int getSingletonCount() {
}
+ 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.
* @param beanName the name of the singleton about to be created
* @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 @@ protected void beforeSingletonCreation(String beanName) {
* @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.
@@ -56,7 +56,6 @@
DisposableBeanMethodInterceptor.class, NoOp.class };
private static final CallbackFilter CALLBACK_FILTER = new CallbackFilter() {
-
public int accept(Method candidateMethod) {
// Set up the callback filter to return the index of the BeanMethodInterceptor when
// handling a @Bean-annotated method; otherwise, return index of the NoOp callback.
@@ -72,7 +71,6 @@ public int accept(Method candidateMethod) {
private static final Callback DISPOSABLE_BEAN_METHOD_INTERCEPTOR = new DisposableBeanMethodInterceptor();
-
private final Callback[] callbackInstances;
@@ -162,6 +160,7 @@ private Enhancer newEnhancer(Class<?> superclass) {
private static class GetObjectMethodInterceptor implements MethodInterceptor {
private final ConfigurableBeanFactory beanFactory;
+
private final String beanName;
public GetObjectMethodInterceptor(ConfigurableBeanFactory beanFactory, String beanName) {
@@ -296,7 +295,8 @@ public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object
this.beanFactory.setCurrentlyInCreation(beanName, false);
}
return this.beanFactory.getBean(beanName);
- } finally {
+ }
+ finally {
if (alreadyInCreation) {
this.beanFactory.setCurrentlyInCreation(beanName, true);
}
@@ -347,6 +347,6 @@ private Object enhanceFactoryBean(Class<?> fbClass, String beanName) throws Inst
Enhancer.registerCallbacks(fbSubclass, callbackInstances);
return fbSubclass.newInstance();
}
-
}
+
}

0 comments on commit f6209cd

Please sign in to comment.