Как Spring определяет, какой именно бин нужно внедрить при наличии нескольких кандидатов?

«Как Spring определяет, какой именно бин нужно внедрить при наличии нескольких кандидатов?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Spring разрешает неоднозначность при внедрении, используя приоритетный порядок. Если в контексте есть несколько бинов одного типа, механизм выбора следующий:

1. Аннотация @Primary — наивысший приоритет. Бин с этой аннотацией выбирается по умолчанию.

@Repository
@Primary // Этот бин будет выбран при инъекции UserRepository
public class JpaUserRepository implements UserRepository {}

@Repository
public class JdbcUserRepository implements UserRepository {}

2. Аннотация @Qualifier — явное указание имени. Позволяет выбрать конкретный бин по его имени (по умолчанию — имя бина).

@Service
public class UserService {
    @Autowired
    @Qualifier("jdbcUserRepository") // Внедрит именно JdbcUserRepository
    private UserRepository userRepository;
}

3. Имя поля/параметра (если не указан @Qualifier). Spring попытается найти бин, имя которого совпадает с именем поля или параметра.

@Autowired
private UserRepository jdbcUserRepository; // Будет искать бин с именем "jdbcUserRepository"

4. Аннотация @Resource (JSR-250). Сначала ищет по имени, затем по типу.

@Resource(name = "mySpecificBean")
private MyService service;

5. Список или Map всех бинов. Если тип зависимости — List<MyInterface> или Map<String, MyInterface>, Spring внедрит все подходящие бины.

@Autowired
private List<Validator> allValidators; // Внедрит все бины типа Validator

@Autowired
private Map<String, Validator> validatorMap; // Ключ — имя бина, значение — сам бин

Если неоднозначность не разрешена, Spring выбросит NoUniqueBeanDefinitionException. Обязательность инъекции регулируется @Autowired(required = false).