Browse Source

Cache bean type next to primary bean names (on singleton creation)

This avoids singleton access for type checks in hasPrimaryConflict.

Closes gh-35330
pull/35405/head
Juergen Hoeller 4 months ago
parent
commit
c248f94e5a
  1. 28
      spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

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

@ -58,6 +58,7 @@ import org.springframework.beans.factory.BeanFactoryAware; @@ -58,6 +58,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
import org.springframework.beans.factory.CannotLoadBeanClassException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InjectionPoint;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
@ -196,8 +197,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -196,8 +197,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
/** Map from bean name to merged BeanDefinitionHolder. */
private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);
/** Set of bean definition names with a primary marker. */
private final Set<String> primaryBeanNames = ConcurrentHashMap.newKeySet(16);
/** Map of bean definition names with a primary marker plus corresponding type. */
private final Map<String, Class<?>> primaryBeanNamesWithType = new ConcurrentHashMap<>(16);
/** Map of singleton and non-singleton bean names, keyed by dependency type. */
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
@ -1037,7 +1038,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -1037,7 +1038,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
protected void cacheMergedBeanDefinition(RootBeanDefinition mbd, String beanName) {
super.cacheMergedBeanDefinition(mbd, beanName);
if (mbd.isPrimary()) {
this.primaryBeanNames.add(beanName);
this.primaryBeanNamesWithType.put(beanName, Void.class);
}
}
@ -1313,7 +1314,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -1313,7 +1314,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
// Cache a primary marker for the given bean.
if (beanDefinition.isPrimary()) {
this.primaryBeanNames.add(beanName);
this.primaryBeanNamesWithType.put(beanName, Void.class);
}
}
@ -1405,7 +1406,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -1405,7 +1406,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
destroySingleton(beanName);
// Remove a cached primary marker for the given bean.
this.primaryBeanNames.remove(beanName);
this.primaryBeanNamesWithType.remove(beanName);
// Notify all post-processors that the specified bean definition has been reset.
for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
@ -1458,9 +1459,18 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -1458,9 +1459,18 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@Override
protected void addSingleton(String beanName, Object singletonObject) {
super.addSingleton(beanName, singletonObject);
Predicate<Class<?>> filter = (beanType -> beanType != Object.class && beanType.isInstance(singletonObject));
this.allBeanNamesByType.keySet().removeIf(filter);
this.singletonBeanNamesByType.keySet().removeIf(filter);
if (this.primaryBeanNamesWithType.containsKey(beanName) && singletonObject.getClass() != NullBean.class) {
Class<?> beanType = (singletonObject instanceof FactoryBean<?> fb ?
getTypeForFactoryBean(fb) : singletonObject.getClass());
if (beanType != null) {
this.primaryBeanNamesWithType.put(beanName, beanType);
}
}
}
@Override
@ -2268,8 +2278,12 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -2268,8 +2278,12 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
* not matching the given bean name.
*/
private boolean hasPrimaryConflict(String beanName, Class<?> dependencyType) {
for (String candidate : this.primaryBeanNames) {
if (isTypeMatch(candidate, dependencyType) && !candidate.equals(beanName)) {
for (Map.Entry<String, Class<?>> candidate : this.primaryBeanNamesWithType.entrySet()) {
String candidateName = candidate.getKey();
Class<?> candidateType = candidate.getValue();
if (!candidateName.equals(beanName) && (candidateType != Void.class ?
dependencyType.isAssignableFrom(candidateType) : // cached singleton class for primary bean
isTypeMatch(candidateName, dependencyType))) { // not instantiated yet or not a singleton
return true;
}
}

Loading…
Cancel
Save