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

Loading…
Cancel
Save