Merge branch '6.2.x'

This commit is contained in:
Juergen Hoeller
2025-02-18 13:14:38 +01:00
7 changed files with 106 additions and 9 deletions

View File

@@ -37,6 +37,7 @@ import org.jspecify.annotations.Nullable;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.util.Assert;
@@ -280,6 +281,25 @@ abstract class AutowireUtils {
}
}
/**
* Check the default-candidate status for the specified bean.
* @param beanFactory the bean factory
* @param beanName the name of the bean to check
* @return whether the specified bean qualifies as a default candidate
* @since 6.2.4
* @see AbstractBeanDefinition#isDefaultCandidate()
*/
public static boolean isDefaultCandidate(ConfigurableBeanFactory beanFactory, String beanName) {
try {
BeanDefinition mbd = beanFactory.getMergedBeanDefinition(beanName);
return (!(mbd instanceof AbstractBeanDefinition abd) || abd.isDefaultCandidate());
}
catch (NoSuchBeanDefinitionException ex) {
// A manually registered singleton instance not backed by a BeanDefinition.
return true;
}
}
/**
* Reflective {@link InvocationHandler} for lazy access to the current target object.

View File

@@ -1479,6 +1479,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
if (candidateName == null) {
candidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass());
}
if (candidateName == null) {
candidateName = determineDefaultCandidate(candidates);
}
if (candidateName != null) {
Object beanInstance = candidates.get(candidateName);
if (beanInstance == null) {
@@ -1939,7 +1942,12 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
if (priorityCandidate != null) {
return priorityCandidate;
}
// Step 4: pick directly registered dependency
// Step 4: pick unique default-candidate
String defaultCandidate = determineDefaultCandidate(candidates);
if (defaultCandidate != null) {
return defaultCandidate;
}
// Step 5: pick directly registered dependency
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateName = entry.getKey();
Object beanInstance = entry.getValue();
@@ -2097,6 +2105,28 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return null;
}
/**
* Return a unique "default-candidate" among remaining non-default candidates.
* @param candidates a Map of candidate names and candidate instances
* (or candidate classes if not created yet) that match the required type
* @return the name of the default candidate, or {@code null} if none found
* @since 6.2.4
* @see AbstractBeanDefinition#isDefaultCandidate()
*/
@Nullable
private String determineDefaultCandidate(Map<String, Object> candidates) {
String defaultBeanName = null;
for (String candidateBeanName : candidates.keySet()) {
if (AutowireUtils.isDefaultCandidate(this, candidateBeanName)) {
if (defaultBeanName != null) {
return null;
}
defaultBeanName = candidateBeanName;
}
}
return defaultBeanName;
}
/**
* Determine whether the given candidate name matches the bean name or the aliases
* stored in this bean definition.

View File

@@ -366,8 +366,18 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
try {
addSingleton(beanName, singletonObject);
}
catch (IllegalStateException ex) {
// Leniently accept same instance if implicitly appeared.
Object object = this.singletonObjects.get(beanName);
if (singletonObject != object) {
throw ex;
}
}
}
}
return singletonObject;