();
Class> beanType = getType(beanName, allowFactoryBeanInit);
if (beanType != null) {
MergedAnnotations.from(beanType, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY)
.stream(annotationType)
.filter(MergedAnnotation::isPresent)
.forEach(mergedAnnotation -> annotations.add(mergedAnnotation.synthesize()));
}
if (containsBeanDefinition(beanName)) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// Check raw bean class, e.g. in case of a proxy.
if (bd.hasBeanClass() && bd.getFactoryMethodName() == null) {
Class> beanClass = bd.getBeanClass();
if (beanClass != beanType) {
MergedAnnotations.from(beanClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY)
.stream(annotationType)
.filter(MergedAnnotation::isPresent)
.forEach(mergedAnnotation -> annotations.add(mergedAnnotation.synthesize()));
}
}
// Check annotations declared on factory method, if any.
Method factoryMethod = bd.getResolvedFactoryMethod();
if (factoryMethod != null) {
MergedAnnotations.from(factoryMethod, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY)
.stream(annotationType)
.filter(MergedAnnotation::isPresent)
.forEach(mergedAnnotation -> annotations.add(mergedAnnotation.synthesize()));
}
}
return annotations;
}
//---------------------------------------------------------------------
// Implementation of ConfigurableBeanFactory interface @since 4.0
//---------------------------------------------------------------------
@Override
public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) {
super.copyConfigurationFrom(otherFactory);
if (otherFactory instanceof StandardBeanFactory std) {
this.bootstrapExecutor = std.bootstrapExecutor;
this.dependencyComparator = std.dependencyComparator;
this.allowEagerClassLoading = std.allowEagerClassLoading;
this.allowBeanDefinitionOverriding = std.allowBeanDefinitionOverriding;
// A clone of the AutowireCandidateResolver since it is potentially BeanFactoryAware
setAutowireCandidateResolver(std.getAutowireCandidateResolver().cloneIfNecessary());
}
}
/**
* Reset all bean definition caches for the given bean,
* including the caches of beans that are derived from it.
* Called after an existing bean definition has been replaced or removed,
* triggering {@link #destroySingleton} and {@link MergedBeanDefinitionPostProcessor#resetBeanDefinition}
* on the given bean.
*
* @param beanName the name of the bean to reset
* @see #registerBeanDefinition
* @see #removeBeanDefinition
*/
protected void resetBeanDefinition(String beanName) {
// Remove the merged bean definition for the given bean, if already created.
clearMergedBeanDefinition(beanName);
// Remove corresponding bean from singleton cache, if any. Shouldn't usually
// be necessary, rather just meant for overriding a context's default beans
destroySingleton(beanName);
// Remove a cached primary marker for the given bean.
primaryBeanNames.remove(beanName);
// Notify all post-processors that the specified bean definition has been reset.
for (MergedBeanDefinitionPostProcessor processor : postProcessors().definitions) {
processor.resetBeanDefinition(beanName);
}
// Reset all bean definitions that have the given bean as parent (recursively).
for (String bdName : this.beanDefinitionNames) {
if (!beanName.equals(bdName)) {
BeanDefinition bd = this.beanDefinitionMap.get(bdName);
// Ensure bd is non-null due to potential concurrent modification of beanDefinitionMap.
if (bd != null && beanName.equals(bd.getParentName())) {
resetBeanDefinition(bdName);
}
}
}
}
@Override
public boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor)
throws NoSuchBeanDefinitionException {
return isAutowireCandidate(beanName, descriptor, getAutowireCandidateResolver());
}
/**
* Determine whether the specified bean definition qualifies as an autowire candidate,
* to be injected into other beans which declare a dependency of matching type.
*
* @param beanName the name of the bean definition to check
* @param descriptor the descriptor of the dependency to resolve
* @param resolver the AutowireCandidateResolver to use for the actual resolution algorithm
* @return whether the bean should be considered as autowire candidate
*/
protected boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor, AutowireCandidateResolver resolver)
throws NoSuchBeanDefinitionException {
String bdName = BeanFactoryUtils.transformedBeanName(beanName);
if (containsBeanDefinition(bdName)) {
return isAutowireCandidate(beanName, getMergedLocalBeanDefinition(bdName), descriptor, resolver);
}
else if (containsSingleton(beanName)) {
return isAutowireCandidate(
beanName, new RootBeanDefinition(getType(beanName)), descriptor, resolver);
}
BeanFactory parent = getParentBeanFactory();
if (parent instanceof StandardBeanFactory) {
// No bean definition found in this factory -> delegate to parent.
return ((StandardBeanFactory) parent).isAutowireCandidate(beanName, descriptor, resolver);
}
else if (parent instanceof AutowireCapableBeanFactory) {
// If no StandardBeanFactory, can't pass the resolver along.
return ((AutowireCapableBeanFactory) parent).isAutowireCandidate(beanName, descriptor);
}
else {
return true;
}
}
/**
* Determine whether the specified bean definition qualifies as an autowire candidate,
* to be injected into other beans which declare a dependency of matching type.
*
* @param beanName the name of the bean definition to check
* @param merged the bean definition to check
* @param descriptor the descriptor of the dependency to resolve
* @param resolver the AutowireCandidateResolver to use for the actual resolution algorithm
* @return whether the bean should be considered as autowire candidate
*/
protected boolean isAutowireCandidate(String beanName, RootBeanDefinition merged,
DependencyDescriptor descriptor, AutowireCandidateResolver resolver) {
String bdName = BeanFactoryUtils.transformedBeanName(beanName);
resolveBeanClass(bdName, merged);
if (merged.isFactoryMethodUnique && merged.factoryMethodToIntrospect == null) {
new ConstructorResolver(this).resolveFactoryMethodIfPossible(merged);
}
BeanDefinitionHolder holder = getHolder(beanName, merged, bdName);
return resolver.isAutowireCandidate(holder, descriptor);
}
private BeanDefinitionHolder getHolder(String beanName, RootBeanDefinition merged, String bdName) {
if (beanName.equals(bdName)) {
return mergedBeanDefinitionHolders.computeIfAbsent(beanName, key -> new BeanDefinitionHolder(merged, beanName, getAliases(bdName)));
}
return new BeanDefinitionHolder(merged, beanName, getAliases(bdName));
}
@Nullable
@Override
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException {
return resolveDependency(descriptor, requestingBeanName, null, null);
}
@Nullable
@Override
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
Class> dependencyType = descriptor.getDependencyType();
if (Optional.class == dependencyType) {
return createOptionalDependency(descriptor, requestingBeanName);
}
else if (Supplier.class == dependencyType
|| ObjectProvider.class == dependencyType) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
else if (injectProviderClass == dependencyType) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else if (descriptor.supportsLazyResolution()) {
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName);
if (result != null) {
return result;
}
}
return doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
// Step 1: pre-resolved shortcut for single bean match, e.g. from @Autowired
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
// Step 2: pre-defined value or expression, e.g. from @Value
Class> type = descriptor.getDependencyType();
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = beanName != null && containsBean(beanName)
? getMergedBeanDefinition(beanName) : null;
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = typeConverter != null ? typeConverter : getTypeConverter();
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return descriptor.getField() != null
? converter.convertIfNecessary(value, type, descriptor.getField())
: converter.convertIfNecessary(value, type, descriptor.getMethodParameter());
}
}
// Step 3: shortcut for declared dependency name or qualifier-suggested name matching target bean name
if (descriptor.usesStandardBeanLookup()) {
String dependencyName = descriptor.getDependencyName();
if (dependencyName == null || !containsBean(dependencyName)) {
String suggestedName = getAutowireCandidateResolver().getSuggestedName(descriptor);
dependencyName = suggestedName != null && containsBean(suggestedName) ? suggestedName : null;
}
if (dependencyName != null) {
dependencyName = canonicalName(dependencyName); // dependency name can be alias of target name
if (isTypeMatch(dependencyName, type) && isAutowireCandidate(dependencyName, descriptor)
&& !isFallback(dependencyName) && !hasPrimaryConflict(dependencyName, type)
&& !isSelfReference(beanName, dependencyName)) {
if (autowiredBeanNames != null) {
autowiredBeanNames.add(dependencyName);
}
Object result = getBean(dependencyName);
if (result == null) {
result = getInjector().resolve(descriptor, dependencyName, autowiredBeanNames, typeConverter, null);
}
return resolveInstance(result, descriptor, type, dependencyName);
}
}
}
// Step 4a: multiple beans as stream / array / standard collection / plain map
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// Step 4b: direct bean matches, possibly direct beans of type Collection / Map
Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
// Step 4c (fallback): custom Collection / Map declarations for collecting multiple beans
multipleBeans = resolveMultipleBeansFallback(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// Raise exception if nothing found for required injection point
Object result = getInjector().resolve(descriptor, beanName, autowiredBeanNames, typeConverter, null);
return resolveInstance(result, descriptor, type, beanName);
}
String autowiredBeanName;
Object instanceCandidate;
// Step 5: determine single candidate
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesArrayCollectionOrMap(type)) {
// Raise exception if no clear match found for required injection point
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
Map.Entry entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
// Step 6: validate single result
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result == null) {
// for user define
result = getInjector().resolve(descriptor, autowiredBeanName, autowiredBeanNames, typeConverter, null);
if (result == null && isRequired(descriptor)) {
if (matchingBeans.size() == 1) {
// factory method returns null
BeanDefinition merged = getMergedBeanDefinition(autowiredBeanName);
String factoryMethodName = merged.getFactoryMethodName();
if (factoryMethodName != null) {
String factoryBeanName = merged.getFactoryBeanName();
if (factoryBeanName == null) {
factoryBeanName = merged.getBeanClassName();
}
throw new FactoryMethodBeanException(merged, descriptor, autowiredBeanName,
"Only one bean which qualifies as autowire candidate, but its factory method '%s' in '%s' returns null"
.formatted(factoryMethodName, factoryBeanName));
}
}
// Raise exception if null encountered for required injection point
raiseNoMatchingBeanFound(type, descriptor);
}
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(
autowiredBeanName, type, instanceCandidate != null ? instanceCandidate.getClass() : NullValue.class);
}
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
@Nullable
private Object resolveInstance(Object candidate, DependencyDescriptor descriptor, Class> type, String name) {
if (candidate == null) {
// Raise exception if null encountered for required injection point
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor);
}
}
if (!ClassUtils.isAssignableValue(type, candidate)) {
throw new BeanNotOfRequiredTypeException(
name, type, candidate != null ? candidate.getClass() : NullValue.class);
}
return candidate;
}
@Nullable
@SuppressWarnings("unchecked")
private T convertIfNecessary(@Nullable Object bean, @Nullable Class> requiredType, @Nullable TypeConverter converter) {
// Check if required type matches the type of the actual bean instance.
if (bean != null && requiredType != null && !ClassUtils.isAssignableValue(requiredType, bean)) {
if (converter == null) {
converter = getTypeConverter();
}
bean = converter.convertIfNecessary(bean, requiredType);
}
return (T) bean;
}
@Nullable
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) {
Class> type = descriptor.getDependencyType();
if (descriptor instanceof StreamDependencyDescriptor streamDescriptor) {
Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
Stream stream = matchingBeans.keySet().stream()
.map(name -> descriptor.resolveCandidate(name, type, this))
.filter(Objects::nonNull);
if (streamDescriptor.isOrdered()) {
stream = stream.sorted(adaptOrderComparator(matchingBeans));
}
return stream;
}
else if (type.isArray()) {
Class> componentType = type.getComponentType();
ResolvableType resolvableType = descriptor.getResolvableType();
Class> resolvedArrayType = resolvableType.resolve(type);
if (resolvedArrayType != type) {
componentType = resolvableType.getComponentType().resolve();
}
if (componentType == null) {
return null;
}
var matchingBeans = findAutowireCandidates(beanName, componentType, new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
Object result = convertIfNecessary(matchingBeans.values(), resolvedArrayType, typeConverter);
if (result instanceof Object[] array && array.length > 1 && descriptor.isOrdered()) {
Comparator comparator = adaptDependencyComparator(matchingBeans);
if (comparator != null) {
Arrays.sort(array, comparator);
}
}
return result;
}
else if (Collection.class == type || Set.class == type || List.class == type) {
return resolveMultipleBeanCollection(descriptor, beanName, autowiredBeanNames, typeConverter);
}
else if (Map.class == type) {
return resolveMultipleBeanMap(descriptor, beanName, autowiredBeanNames, typeConverter);
}
else {
return null;
}
}
@Nullable
private Object resolveMultipleBeansFallback(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) {
Class> type = descriptor.getDependencyType();
if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
return resolveMultipleBeanCollection(descriptor, beanName, autowiredBeanNames, typeConverter);
}
else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
return resolveMultipleBeanMap(descriptor, beanName, autowiredBeanNames, typeConverter);
}
return null;
}
@Nullable
private Object resolveMultipleBeanCollection(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) {
Class> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
if (elementType == null) {
return null;
}
Map matchingBeans = findAutowireCandidates(
beanName, elementType, new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
Object result = convertIfNecessary(matchingBeans.values(), descriptor.getDependencyType(), typeConverter);
if (result instanceof List> list && list.size() > 1 && descriptor.isOrdered()) {
Comparator comparator = adaptDependencyComparator(matchingBeans);
if (comparator != null) {
list.sort(comparator);
}
}
return result;
}
@Nullable
private Object resolveMultipleBeanMap(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) {
ResolvableType mapType = descriptor.getResolvableType().asMap();
Class> keyType = mapType.resolveGeneric(0);
if (String.class != keyType) {
return null;
}
Class> valueType = mapType.resolveGeneric(1);
if (valueType == null) {
return null;
}
Map matchingBeans = findAutowireCandidates(
beanName, valueType, new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
return converter.convertIfNecessary(matchingBeans, descriptor.getDependencyType());
}
boolean isRequired(DependencyDescriptor descriptor) {
return getAutowireCandidateResolver().isRequired(descriptor);
}
private boolean indicatesArrayCollectionOrMap(Class> type) {
return type.isArray() || (type.isInterface()
&& (Collection.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type)));
}
@Nullable
private Comparator adaptDependencyComparator(Map matchingBeans) {
Comparator comparator = getDependencyComparator();
if (comparator instanceof OrderComparator) {
return ((OrderComparator) comparator).withSourceProvider(
createFactoryAwareOrderSourceProvider(matchingBeans));
}
else {
return comparator;
}
}
/**
* Find bean instances that match the required type.
* Called during autowiring for the specified bean.
*
* @param beanName the name of the bean that is about to be wired
* @param requiredType the actual type of bean to look for
* (may be an array component type or collection element type)
* @param descriptor the descriptor of the dependency to resolve
* @return a Map of candidate names and candidate instances that match
* the required type (never {@code null})
* @throws BeansException in case of errors
*/
protected Map findAutowireCandidates(@Nullable String beanName, Class> requiredType, DependencyDescriptor descriptor) {
Set candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map result = CollectionUtils.newLinkedHashMap(candidateNames.size());
for (Map.Entry, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
Class> autowiringType = classObjectEntry.getKey();
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = AutowireUtils.resolveAutowiringValue(classObjectEntry.getValue(), requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty()) {
boolean multiple = indicatesArrayCollectionOrMap(requiredType);
// Consider fallback matches if the first pass failed to find anything...
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate)
&& isAutowireCandidate(candidate, fallbackDescriptor)
&& (!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty() && !multiple) {
// Consider self references as a final pass...
// but in the case of a dependency collection, not the very same bean itself.
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate)
&& (!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate))
&& isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}
/**
* Add an entry to the candidate map: a bean instance if available or just the resolved
* type, preventing early bean initialization ahead of primary candidate selection.
*/
private void addCandidateEntry(Map candidates,
String candidateName, DependencyDescriptor descriptor, Class> requiredType) {
if (descriptor instanceof MultiElementDescriptor) {
Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
if (beanInstance != null) {
candidates.put(candidateName, beanInstance);
}
}
else if (containsSingleton(candidateName)
|| (descriptor instanceof StreamDependencyDescriptor streamDescriptor && streamDescriptor.isOrdered())) {
Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
candidates.put(candidateName, beanInstance);
}
else {
candidates.put(candidateName, getType(candidateName));
}
}
/**
* Determine the autowire candidate in the given set of beans.
* Looks for {@code @Primary} and {@code @Priority} (in that order).
*
* @param candidates a Map of candidate names and candidate instances
* that match the required type, as returned by {@link #findAutowireCandidates}
* @param descriptor the target dependency to match against
* @return the name of the autowire candidate, or {@code null} if none found
*/
@Nullable
protected String determineAutowireCandidate(Map candidates, DependencyDescriptor descriptor) {
Class> requiredType = descriptor.getDependencyType();
// Step 1: check primary candidate
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
if (primaryCandidate != null) {
return primaryCandidate;
}
// Step 2a: match bean name against declared dependency name
String dependencyName = descriptor.getDependencyName();
if (dependencyName != null) {
for (String beanName : candidates.keySet()) {
if (matchesBeanName(beanName, dependencyName)) {
return beanName;
}
}
}
// Step 2b: match bean name against qualifier-suggested name
String suggestedName = getAutowireCandidateResolver().getSuggestedName(descriptor);
if (suggestedName != null) {
for (String beanName : candidates.keySet()) {
if (matchesBeanName(beanName, suggestedName)) {
return beanName;
}
}
}
// Step 3: check highest priority candidate
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
if (priorityCandidate != null) {
return priorityCandidate;
}
// Step 4: pick directly registered dependency
for (Map.Entry entry : candidates.entrySet()) {
Object beanInstance = entry.getValue();
if (beanInstance != null && resolvableDependencies.containsValue(beanInstance)) {
return entry.getKey();
}
}
return null;
}
/**
* Determine the primary candidate in the given set of beans.
*
* @param candidates a Map of candidate names and candidate instances
* (or candidate classes if not created yet) that match the required type
* @param requiredType the target dependency type to match against
* @return the name of the primary candidate, or {@code null} if none found
* @see #isPrimary(String, Object)
*/
@Nullable
protected String determinePrimaryCandidate(Map candidates, Class> requiredType) {
String primaryBeanName = null;
// First pass: identify unique primary candidate
for (Map.Entry entry : candidates.entrySet()) {
String candidateBeanName = entry.getKey();
Object beanInstance = entry.getValue();
if (isPrimary(candidateBeanName, beanInstance)) {
if (primaryBeanName != null) {
boolean candidateLocal = containsBeanDefinition(candidateBeanName);
boolean primaryLocal = containsBeanDefinition(primaryBeanName);
if (candidateLocal == primaryLocal) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
"more than one 'primary' bean found among candidates: " + candidates.keySet());
}
else if (candidateLocal) {
primaryBeanName = candidateBeanName;
}
}
else {
primaryBeanName = candidateBeanName;
}
}
}
// Second pass: identify unique non-fallback candidate
if (primaryBeanName == null) {
for (String candidateBeanName : candidates.keySet()) {
if (!isFallback(candidateBeanName)) {
if (primaryBeanName != null) {
return null;
}
primaryBeanName = candidateBeanName;
}
}
}
return primaryBeanName;
}
/**
* Determine the candidate with the highest priority in the given set of beans.
* Based on {@code @jakarta.annotation.Priority}. As defined by the related
* {@link Ordered} interface, the lowest value has
* the highest priority.
*
* @param candidates a Map of candidate names and candidate instances
* (or candidate classes if not created yet) that match the required type
* @param requiredType the target dependency type to match against
* @return the name of the candidate with the highest priority,
* or {@code null} if none found
* @see #getPriority(Object)
*/
@Nullable
protected String determineHighestPriorityCandidate(Map candidates, Class> requiredType) {
String highestPriorityBeanName = null;
Integer highestPriority = null;
boolean highestPriorityConflictDetected = false;
for (Map.Entry entry : candidates.entrySet()) {
String candidateBeanName = entry.getKey();
Object beanInstance = entry.getValue();
if (beanInstance != null) {
Integer candidatePriority = getPriority(beanInstance);
if (candidatePriority != null) {
if (highestPriority != null) {
if (candidatePriority.equals(highestPriority)) {
highestPriorityConflictDetected = true;
}
else if (candidatePriority < highestPriority) {
highestPriorityBeanName = candidateBeanName;
highestPriority = candidatePriority;
highestPriorityConflictDetected = false;
}
}
else {
highestPriorityBeanName = candidateBeanName;
highestPriority = candidatePriority;
}
}
}
}
if (highestPriorityConflictDetected) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
"Multiple beans found with the same highest priority (%d) among candidates: %s"
.formatted(highestPriority, candidates.keySet()));
}
return highestPriorityBeanName;
}
/**
* Return whether the bean definition for the given bean name has been
* marked as a primary bean.
*
* @param beanName the name of the bean
* @param beanInstance the corresponding bean instance (can be null)
* @return whether the given bean qualifies as primary
*/
protected boolean isPrimary(String beanName, Object beanInstance) {
String transformedBeanName = transformedBeanName(beanName);
if (containsBeanDefinition(transformedBeanName)) {
return getMergedLocalBeanDefinition(transformedBeanName).isPrimary();
}
return getParentBeanFactory() instanceof StandardBeanFactory std
&& std.isPrimary(transformedBeanName, beanInstance);
}
/**
* Return whether the bean definition for the given bean name has been
* marked as a fallback bean.
*
* @param beanName the name of the bean
*/
private boolean isFallback(String beanName) {
String transformedBeanName = transformedBeanName(beanName);
if (containsBeanDefinition(transformedBeanName)) {
return getMergedLocalBeanDefinition(transformedBeanName).isFallback();
}
return getParentBeanFactory() instanceof StandardBeanFactory parent
&& parent.isFallback(transformedBeanName);
}
/**
* Return the priority assigned for the given bean instance by
* the {@code jakarta.annotation.Priority} annotation.
* The default implementation delegates to the specified
* {@link #setDependencyComparator dependency comparator}, checking its
* {@link OrderComparator#getPriority method} if it is an extension of
* Framework's common {@link OrderComparator} - typically, an
* {@link AnnotationAwareOrderComparator}.
* If no such comparator is present, this implementation returns {@code null}.
*
* @param beanInstance the bean instance to check (can be {@code null})
* @return the priority assigned to that bean or {@code null} if none is set
*/
@Nullable
protected Integer getPriority(Object beanInstance) {
Comparator comparator = getDependencyComparator();
if (comparator instanceof OrderComparator) {
return ((OrderComparator) comparator).getPriority(beanInstance);
}
return null;
}
/**
* Determine whether the given candidate name matches the bean name or the aliases
* stored in this bean definition.
*/
protected boolean matchesBeanName(String beanName, @Nullable String candidateName) {
if (candidateName != null) {
return candidateName.equals(beanName)
|| ObjectUtils.containsElement(getAliases(beanName), candidateName);
}
return false;
}
/**
* Determine whether the given beanName/candidateName pair indicates a self reference,
* i.e. whether the candidate points back to the original bean or to a factory method
* on the original bean.
*/
private boolean isSelfReference(@Nullable String beanName, @Nullable String candidateName) {
return (beanName != null && candidateName != null &&
(beanName.equals(candidateName) || (containsBeanDefinition(candidateName)
&& beanName.equals(getMergedLocalBeanDefinition(candidateName).getFactoryBeanName()))));
}
/**
* Determine whether there is a primary bean registered for the given dependency type,
* 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)) {
return true;
}
}
return getParentBeanFactory() instanceof StandardBeanFactory parent
&& parent.hasPrimaryConflict(beanName, dependencyType);
}
/**
* Raise a NoSuchBeanDefinitionException or BeanNotOfRequiredTypeException
* for an unresolvable dependency.
*/
void raiseNoMatchingBeanFound(Class> type, DependencyDescriptor descriptor) throws BeansException {
checkBeanNotOfRequiredType(type, descriptor);
raiseNoMatchingBeanFound(descriptor);
}
static void raiseNoMatchingBeanFound(DependencyDescriptor descriptor) {
throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(),
"expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: "
+ ObjectUtils.nullSafeToString(descriptor.getAnnotations()));
}
/**
* Raise a BeanNotOfRequiredTypeException for an unresolvable dependency, if applicable,
* i.e. if the target type of the bean would match but an exposed proxy doesn't.
*/
private void checkBeanNotOfRequiredType(Class> type, DependencyDescriptor descriptor) {
AutowireCandidateResolver candidateResolver = getAutowireCandidateResolver();
for (String beanName : beanDefinitionNames) {
try {
RootBeanDefinition merged = getMergedLocalBeanDefinition(beanName);
Class> targetType = merged.getTargetType();
if (targetType != null && type.isAssignableFrom(targetType)
&& isAutowireCandidate(beanName, merged, descriptor, candidateResolver)) {
// Probably a proxy interfering with target type match -> throw meaningful exception.
Object beanInstance = getSingleton(beanName, false);
Class> beanType = (beanInstance == null || beanInstance == NullValue.INSTANCE)
? predictBeanType(beanName, merged) : beanInstance.getClass();
if (beanType != null && !type.isAssignableFrom(beanType)) {
throw new BeanNotOfRequiredTypeException(beanName, type, beanType);
}
}
}
catch (NoSuchBeanDefinitionException ex) {
// Bean definition got removed while we were iterating -> ignore.
}
}
if (getParentBeanFactory() instanceof StandardBeanFactory parent) {
parent.checkBeanNotOfRequiredType(type, descriptor);
}
}
/**
* Create an {@link Optional} wrapper for the specified dependency.
*/
private Optional> createOptionalDependency(DependencyDescriptor descriptor, @Nullable String beanName, final Object... args) {
DependencyDescriptor descriptorToUse = new NestedDependencyDescriptor(descriptor) {
@Override
public boolean isRequired() {
return false;
}
@Override
public Object resolveCandidate(String beanName, Class> requiredType, BeanFactory beanFactory) {
return ObjectUtils.isNotEmpty(args)
? beanFactory.getBean(beanName, args)
: super.resolveCandidate(beanName, requiredType, beanFactory);
}
@Override
public boolean usesStandardBeanLookup() {
return ObjectUtils.isEmpty(args);
}
};
Object result = doResolveDependency(descriptorToUse, beanName, null, null);
return result instanceof Optional ? (Optional>) result : Optional.ofNullable(result);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(ObjectUtils.identityToString(this));
sb.append(": defining beans [");
sb.append(StringUtils.collectionToCommaDelimitedString(beanDefinitionNames));
sb.append("]; ");
BeanFactory parent = getParentBeanFactory();
if (parent == null) {
sb.append("root of factory hierarchy");
}
else {
sb.append("parent: ").append(ObjectUtils.identityToString(parent));
}
return sb.toString();
}
//---------------------------------------------------------------------
// Serialization support
//---------------------------------------------------------------------
@Serial
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
throw new NotSerializableException("StandardBeanFactory itself is not deserializable - " +
"just a SerializedBeanFactoryReference is");
}
@Serial
protected Object writeReplace() throws ObjectStreamException {
if (this.serializationId != null) {
return new SerializedBeanFactoryReference(this.serializationId);
}
else {
throw new NotSerializableException("StandardBeanFactory has no serialization id");
}
}
/**
* Minimal id reference to the factory.
* Resolved to the actual factory instance on deserialization.
*/
private static class SerializedBeanFactoryReference implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private final String id;
public SerializedBeanFactoryReference(String id) {
this.id = id;
}
@Serial
private Object readResolve() {
Reference> ref = serializableFactories.get(this.id);
if (ref != null) {
Object result = ref.get();
if (result != null) {
return result;
}
}
// Lenient fallback: dummy factory in case of original factory not found...
StandardBeanFactory dummyFactory = new StandardBeanFactory();
dummyFactory.serializationId = this.id;
return dummyFactory;
}
}
private interface BeanObjectProvider extends ObjectProvider, Serializable { }
/**
* A dependency descriptor marker for nested elements.
*/
private static class NestedDependencyDescriptor extends DependencyDescriptor {
@Serial
private static final long serialVersionUID = 1L;
public NestedDependencyDescriptor(DependencyDescriptor original) {
super(original);
increaseNestingLevel();
}
@Override
public boolean usesStandardBeanLookup() {
return true;
}
}
/**
* A dependency descriptor for a multi-element declaration with nested elements.
*/
private static class MultiElementDescriptor extends NestedDependencyDescriptor {
@Serial
private static final long serialVersionUID = 1L;
public MultiElementDescriptor(DependencyDescriptor original) {
super(original);
}
}
/**
* A dependency descriptor marker for stream access to multiple elements.
*/
private static class StreamDependencyDescriptor extends DependencyDescriptor {
@Serial
private static final long serialVersionUID = 1L;
private final boolean ordered;
public StreamDependencyDescriptor(DependencyDescriptor original, boolean ordered) {
super(original);
this.ordered = ordered;
}
@Override
public boolean isOrdered() {
return this.ordered;
}
}
/**
* Serializable ObjectFactory/ObjectProvider for lazy resolution of a dependency.
*/
private class DependencyObjectProvider implements BeanObjectProvider {
@Serial
private static final long serialVersionUID = 1L;
@Nullable
private final String beanName;
private final boolean optional;
private final DependencyDescriptor descriptor;
public DependencyObjectProvider(DependencyDescriptor descriptor, @Nullable String beanName) {
this.beanName = beanName;
descriptor = new NestedDependencyDescriptor(descriptor);
this.optional = descriptor.getDependencyType() == Optional.class;
this.descriptor = descriptor;
}
@Override
public Object get() throws BeansException {
if (this.optional) {
return createOptionalDependency(this.descriptor, this.beanName);
}
else {
Object result = doResolveDependency(this.descriptor, this.beanName, null, null);
if (result == null) {
throw new NoSuchBeanDefinitionException(this.descriptor.getResolvableType());
}
return result;
}
}
@Override
public Object get(final Object... args) throws BeansException {
if (this.optional) {
return createOptionalDependency(this.descriptor, this.beanName, args);
}
else {
DependencyDescriptor descriptorToUse = new DependencyDescriptor(this.descriptor) {
@Override
public Object resolveCandidate(String beanName, Class> requiredType, BeanFactory beanFactory) {
return beanFactory.getBean(beanName, args);
}
};
Object result = doResolveDependency(descriptorToUse, this.beanName, null, null);
if (result == null) {
throw new NoSuchBeanDefinitionException(this.descriptor.getResolvableType());
}
return result;
}
}
@Override
@Nullable
public Object getIfAvailable() throws BeansException {
try {
if (this.optional) {
return createOptionalDependency(this.descriptor, this.beanName);
}
else {
DependencyDescriptor descriptorToUse = new DependencyDescriptor(this.descriptor) {
@Override
public boolean isRequired() {
return false;
}
@Override
public boolean usesStandardBeanLookup() {
return true;
}
};
return doResolveDependency(descriptorToUse, this.beanName, null, null);
}
}
catch (ScopeNotActiveException ex) {
// Ignore resolved bean in non-active scope
return null;
}
}
@Override
public boolean ifAvailable(Consumer dependencyConsumer) throws BeansException {
Object dependency = getIfAvailable();
if (dependency != null) {
try {
dependencyConsumer.accept(dependency);
return true;
}
catch (ScopeNotActiveException ex) {
// Ignore resolved bean in non-active scope, even on scoped proxy invocation
}
}
return false;
}
@Override
@Nullable
public Object getIfUnique() throws BeansException {
DependencyDescriptor descriptorToUse = new DependencyDescriptor(this.descriptor) {
@Override
public boolean isRequired() {
return false;
}
@Override
@Nullable
public Object resolveNotUnique(ResolvableType type, Map matchingBeans) {
return null;
}
@Override
public boolean usesStandardBeanLookup() {
return true;
}
};
try {
if (this.optional) {
return createOptionalDependency(descriptorToUse, this.beanName);
}
else {
return doResolveDependency(descriptorToUse, this.beanName, null, null);
}
}
catch (ScopeNotActiveException ex) {
// Ignore resolved bean in non-active scope
return null;
}
}
@Override
public boolean ifUnique(Consumer dependencyConsumer) throws BeansException {
Object dependency = getIfUnique();
if (dependency != null) {
try {
dependencyConsumer.accept(dependency);
return true;
}
catch (ScopeNotActiveException ex) {
// Ignore resolved bean in non-active scope, even on scoped proxy invocation
}
}
return false;
}
@Nullable
protected Object getValue() throws BeansException {
if (this.optional) {
return createOptionalDependency(this.descriptor, this.beanName);
}
else {
return doResolveDependency(this.descriptor, this.beanName, null, null);
}
}
@Override
public Stream stream() {
return resolveStream(false);
}
@Override
public Stream orderedStream() {
return resolveStream(true);
}
@SuppressWarnings("unchecked")
private Stream resolveStream(boolean ordered) {
DependencyDescriptor descriptorToUse = new StreamDependencyDescriptor(descriptor, ordered);
Object result = doResolveDependency(descriptorToUse, this.beanName, null, null);
return result instanceof Stream ? (Stream) result : Stream.of(result);
}
}
/**
* Separate inner class for avoiding a hard dependency on the {@code jakarta.inject} API.
* Actual {@code jakarta.inject.Provider} implementation is nested here in order to make it
* invisible for Graal's introspection of StandardBeanFactory's nested classes.
*/
private class Jsr330Factory implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
public Object createDependencyProvider(DependencyDescriptor descriptor, @Nullable String beanName) {
return new Jsr330Provider(descriptor, beanName);
}
private class Jsr330Provider extends DependencyObjectProvider implements Provider {
@Serial
private static final long serialVersionUID = 1L;
public Jsr330Provider(DependencyDescriptor descriptor, @Nullable String beanName) {
super(descriptor, beanName);
}
@Override
@Nullable
public Object get() throws BeansException {
return getValue();
}
}
}
/**
* An {@link OrderSourceProvider} implementation
* that is aware of the bean metadata of the instances to sort.
* Lookup for the method factory of an instance to sort, if any, and let the
* comparator retrieve the {@link Order}
* value defined on it. This essentially allows for the following construct:
*
*
this class takes the {@link AbstractBeanDefinition#ORDER_ATTRIBUTE}
* attribute into account.
*
* @author Harry Yang
* @since 4.0 2021/12/19 17:26
*/
final class FactoryAwareOrderSourceProvider implements OrderSourceProvider {
private final IdentityHashMap instancesToBeanNames;
public FactoryAwareOrderSourceProvider(Map beans) {
this.instancesToBeanNames = new IdentityHashMap<>();
for (Map.Entry entry : beans.entrySet()) {
instancesToBeanNames.put(entry.getValue(), entry.getKey());
}
}
@Override
@Nullable
public Object getOrderSource(Object obj) {
String beanName = this.instancesToBeanNames.get(obj);
if (beanName == null) {
return null;
}
try {
var beanDefinition = (RootBeanDefinition) getMergedBeanDefinition(beanName);
ArrayList sources = new ArrayList<>(3);
Object orderAttribute = beanDefinition.getAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE);
if (orderAttribute != null) {
if (orderAttribute instanceof Integer order) {
sources.add((Ordered) () -> order);
}
else {
throw new IllegalStateException("Invalid value type for attribute '%s': %s"
.formatted(AbstractBeanDefinition.ORDER_ATTRIBUTE, orderAttribute.getClass().getName()));
}
}
Method factoryMethod = beanDefinition.getResolvedFactoryMethod();
if (factoryMethod != null) {
sources.add(factoryMethod);
}
Class> targetType = beanDefinition.getTargetType();
if (targetType != null && targetType != obj.getClass()) {
sources.add(targetType);
}
return sources.toArray();
}
catch (NoSuchBeanDefinitionException ex) {
return null;
}
}
}
private enum PreInstantiation {
MAIN, BACKGROUND
}
}