Как Spring выполняет автоматическое связывание по имени, когда найдено более одного подходящего bean-компонента?

107

Предположим, у меня есть такие интерфейсы:

interface Country {}
class USA implements Country {}
class UK implements Country ()

И этот фрагмент конфигурации xml:

<bean class="USA"/>
<bean id="country" class="UK"/>
<bean id="main" class="Main"/>

Как я могу контролировать, какая зависимость автоматически подключается ниже? Мне нужен британский.

class Main {
    private Country country;
    @Autowired
    public void setCountry(Country country) {
        this.country = country;
    }
}

Я использую Spring 3.0.3.RELEASE.

Маниганда Пракаш
источник
Подумал, что добавлю, что в одной (тестовой) среде я получал «Нет уникального bean типа ...», и в моей среде разработки он работал нормально. Я уверен, что это было что-то вроде пути к классам, но оказалось, что если вы добавите @Qualifier, все сработает нормально.
markthegrea

Ответы:

113

Это описано в разделе 3.9.3 руководства Spring 3.0:

Для резервного совпадения имя bean-компонента считается значением квалификатора по умолчанию.

Другими словами, поведение по умолчанию такое, как если бы вы добавили @Qualifier("country")метод установки.

Скаффман
источник
Когда вы говорите «имя компонента», вы имеете в виду имя поля, которое будет содержать компонент? (то есть в данном случае country)
иск Фонда Моники
67

Вы можете использовать аннотацию @Qualifier

От сюда

Тонкая настройка автосоединения на основе аннотаций с квалификаторами

Поскольку автоматическое подключение по типу может привести к появлению нескольких кандидатов, часто необходимо иметь больший контроль над процессом выбора. Один из способов добиться этого - использовать аннотацию Spring @Qualifier. Это позволяет связывать значения квалификаторов с конкретными аргументами, сужая набор соответствий типов, так что для каждого аргумента выбирается конкретный компонент. В простейшем случае это может быть простое описательное значение:

class Main {
    private Country country;
    @Autowired
    @Qualifier("country")
    public void setCountry(Country country) {
        this.country = country;
    }
}

Это будет использовать UK, добавить идентификатор к bean-компоненту USA и использовать его, если вы хотите США.

Пол Уилан
источник
12

Другой способ добиться того же результата - использовать аннотацию @Value:

public class Main {
     private Country country;

     @Autowired
     public void setCountry(@Value("#{country}") Country country) {
          this.country = country;
     }
}

В этом случае "#{country}строка является выражением Spring Expression Language (SpEL), результатом которого является именованный компонент country.

Рикардо Вегилья
источник
это может быть введено на основе собственности? что, если США или Великобритания - это какой-то параметр, поступающий из URL-адреса, и я хочу ввести 2 разные вещи в зависимости от того, что это за параметр?
Kalpesh Soni
6

Еще одно решение с разрешением по имени:

@Resource(name="country")

Он использует пакет javax.annotation , поэтому он не относится к Spring, но Spring поддерживает его.

тема
источник
1
но @Resourceне будет
Дирк Хоффманн,
5

в некоторых случаях можно использовать аннотацию @Primary.

@Primary
class USA implements Country {}

Таким образом, он будет выбран в качестве кандидата автосоединения по умолчанию, без необходимости автосоединения кандидата на другом компоненте.

для более подробной информации посмотрите на Autowiring двух beans, реализующего один и тот же интерфейс - как установить bean по умолчанию на autowire?

Михаил Дмитряха
источник