118
votes

Suppose I have interfaces such as these:

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

And this snippet of configuration xml:

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

How can I control which dependency is autowired below? I'd like the UK one.

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

I am using Spring 3.0.3.RELEASE.

5
Thought I would add that I was getting a "No unique bean of type..." in one (test) environment and it worked fine in my development environment. I am sure it was some kind of classpath thing, but turned out, if you add the @Qualifier, it worked fine.markthegrea

5 Answers

125
votes

This is documented in section 3.9.3 of the Spring 3.0 manual:

For a fallback match, the bean name is considered a default qualifier value.

In other words, the default behaviour is as though you'd added @Qualifier("country") to the setter method.

76
votes

You can use the @Qualifier annotation

From here

Fine-tuning annotation-based autowiring with qualifiers

Since autowiring by type may lead to multiple candidates, it is often necessary to have more control over the selection process. One way to accomplish this is with Spring's @Qualifier annotation. This allows for associating qualifier values with specific arguments, narrowing the set of type matches so that a specific bean is chosen for each argument. In the simplest case, this can be a plain descriptive value:

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

This will use the UK add an id to USA bean and use that if you want the USA.

12
votes

Another way of achieving the same result is to use the @Value annotation:

public class Main {
     private Country country;

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

In this case, the "#{country} string is an Spring Expression Language (SpEL) expression which evaluates to a bean named country.

6
votes

in some case you can use annotation @Primary.

@Primary
class USA implements Country {}

This way it will be selected as the default autowire candididate, with no need to autowire-candidate on the other bean.

for mo deatils look at Autowiring two beans implementing same interface - how to set default bean to autowire?

6
votes

One more solution with resolving by name:

@Resource(name="country")

It uses javax.annotation package, so it's not Spring specific, but Spring supports it.