Person.java
@Controller
public class Person
{
@Autowired
private Ability ability;
public void printMessage(){
ability.printMessasge();
}
public void setOutputGenerator( Ability ability) {
this.ability = ability;
}
}
Ability.java
@Controller
public class Ability
{
void printMessasge(){
System.out.println("I print message");
}
}
spring.xml
<bean id="invisible" class="com.mkyong.common.Ability" >
</bean>
<context:component-scan base-package="com.mkyong" />
App.java
public class App {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"spring.xml");
Person person = (Person) context.getBean("person");
person.printMessage( );
}
In the above example i have defined two beans of Ability
class one using @Controller
and one in xml
file. According to Autowire
by type i should get
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException:
...
No unique bean of type [com.mkyong.common.Ability] is defined:
But i am getting proper output. Why?
And if i create an interface which Ability class implements then i would get UnsatisfiedDependencyException exception. Like this:
Parent.java
public interface Parent{
public void printMessasge();
}
Ability.java
@Controller
public class Ability implements Parent
{
void printMessasge(){
System.out.println("I print message");
}
Person.java
@Controller
public class Person
{
@Autowired
Parent parent;
public void printMessage(){
parent.printMessasge();
}
public void setOutputGenerator( Parent parent) {
this.parent= parent;
}
}
By default Spring indeed matches by type, but in case of multiple matching beans, it falls back to matching by name. The reference ( 6.9.4 Fine-tuning annotation-based autowiring with qualifiers ) says:
For a fallback match, the bean name is considered a default qualifier value.
Using the @Qualifier
annotation makes the autowiring by type and additionally by name more explicit.
You are not going to get a UnsatisfiedDependencyException
with this configuration because Spring is smart enough to also look at the name of your required dependency, as @Adam writes in his answer. So even if the default autowiring mode is by type and there are two beans of the same type for that dependency, Spring is able to solve the conflict.
This behavior is described in the official documentation, 6.9.4 Fine-tuning annotation-based autowiring with qualifiers section. More details about autowiring modes can be found 6.4.5 Autowiring collaborators .
If you change the name of Person.ability field to something else, like Person.ability2, then Spring will throw a org.springframework.beans.factory.NoUniqueBeanDefinitionException
. It cannot decide which bean it should wire for the Person.ability2 field because:
com.mkyong.common.Ability
type in the context EDIT: in the second case you mention (with the interface), Spring throws the exception for the same bean naming reason I explained above.
Official documentation references:
you have two ambiguous beans defined, when spring try find the bean via type it finds two beans, one via scan other explicitly defined in spring.xml. use @Qualifier to mark the correct bean loaded in Person class. So probably you want like this,
@Controller
public class Person
{
@Autowired
@Qualifier("invisible")
private Ability ability;
public void printMessage(){
ability.printMessasge();
}
public void setOutputGenerator( Ability ability) {
this.ability = ability;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.