When Spring performs autowiring, it expects exactly one bean of the required type to satisfy a dependency. If multiple candidates exist—such as two @Component classes implementing the same interface—the container throws NoUniqueBeanDefinitionException, indicating ambiguity during bean resolution.
Root Cause
This exception arises because Spring’s default autowiring mode (byType) scans the application context for all beans matching the declared field or parameter type. When more than one qualifies (e.g., both Dog and Bee implement Animal), Spring cannot decide which to inject without additional guidance.
Reproducible Example
Consider this minimal setup:
public interface Animal {
String makeSound();
}
@Component
public class Dog implements Animal {
@Override
public String makeSound() {
return "Woof";
}
}
@Component
public class Bee implements Animal {
@Override
public String makeSound() {
return "Buzz";
}
}
@Service
public class Habitat {
@Autowired
private Animal creature; // ← Ambiguity: Dog or Bee?
}
Startup fails with: NoUniqueBeanDefinitionException: No qualifying bean of type 'Animal' available: expected single matching bean but found 2.
Five Effectiev Resolution Strategies
1. Leverage Field Name Matching
Spring fals back to byName matching when byType yields multiple matches. Naming the field after the desired bean’s default name resolves it:
@Service
public class Habitat {
@Autowired
private Animal dog; // Resolves to bean named "dog"
}
2. Inject Concrete Type Instead of Interface
Declare the dependency using the implementation class directly. Spring then matches by exact type:
@Service
public class Habitat {
@Autowired
private Dog pet; // Only Dog matches — no ambiguity
}
3. Designate a Primary Cendidate
Use @Primary on the preferred implementation to signal precedence among peers:
@Component
@Primary
public class Dog implements Animal {
@Override
public String makeSound() {
return "Woof";
}
}
4. Explicit Bean Selection via @Qualifier
Pair @Qualifier with @Autowired to specify the bean’s logical name:
@Service
public class Habitat {
@Autowired
@Qualifier("dog")
private Animal companion;
}
5. Qualify Constructor or Setter Parameters
Apply @Qualifier at method or constructor parameter level for fine-grained control:
@Service
public class Habitat {
private final Animal resident;
public Habitat(@Qualifier("bee") Animal animal) {
this.resident = animal;
}
}
Alternatively, use setter injection:
@Service
public class Habitat {
private Animal resident;
@Autowired
public void assign(@Qualifier("dog") Animal animal) {
this.resident = animal;
}
}