Skip to content

Autowiring fails if multiple non-highest @Priority beans exist with same priority #33733

@xinbimingjingtai

Description

@xinbimingjingtai

Overview

When I was reading the source code for DefaultListableBeanFactory#determineHighestPriorityCandidate(), I found that when multiple beans have the same priority but not the highest priority, the highest priority bean cannot be obtained correctly.

Example

Consider the following scenario:

public interface IFacade {
}

@Priority(10)
@Service
public class Facade0 implements IFacade{
}

@Priority(9)
@Service
public class Facade1 implements IFacade{
}

@Priority(9)
@Service
public class Facade2 implements IFacade{
}

@Priority(8)
@Service
public class Facade3 implements IFacade{
}

@Component
public class Config {

    @Autowired
    private IFacade facade;

}

Proposal

I know that @Qualifier or @Primary can be used to handle this situation, but in this case, the highest priority bean is only Facade3, which should be correctly injected into Config instead of throwing an exception.

Can you consider adding the highest priority results to a List (refer to the code below) and throwing an exception if there are multiple beans with the highest priority?

    @Nullable
    protected String determineHighestPriorityCandidate(Map<String, Object> candidates, Class<?> requiredType) {
        List<String> highestPriorityBeanNames = new ArrayList<>();
        Integer highestPriority = null;
        for (Map.Entry<String, Object> entry : candidates.entrySet()) {
            String candidateBeanName = entry.getKey();
            Object beanInstance = entry.getValue();
            if (beanInstance != null) {
                Integer candidatePriority = getPriority(beanInstance);
                if (candidatePriority != null) {
                    if (!highestPriorityBeanNames.isEmpty()) {
                        if (candidatePriority.equals(highestPriority)) {
                            highestPriorityBeanNames.add(candidateBeanName);
                        }
                        else if (candidatePriority < highestPriority) {
                            highestPriorityBeanNames.clear();
                            highestPriorityBeanNames.add(candidateBeanName);
                            highestPriority = candidatePriority;
                        }
                    }
                    else {
                        highestPriorityBeanNames.add(candidateBeanName);
                        highestPriority = candidatePriority;
                    }
                }
            }
        }
        if (highestPriorityBeanNames.size() > 1) {
            throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
                    "Multiple beans found with the same priority ('" + highestPriority +
                            "') among candidates: " + candidates.keySet());
        }
        return highestPriorityBeanNames.isEmpty() ? null : highestPriorityBeanNames.get(0);
    }

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions