Ambiguous situations
When using autowiring, if there are multiple beans that can match, an error will be generated
E.g:
//某方法 @Autowired public void setDessert(Dessert dessert){ this.dessert = dessert; } // There are 3 classes that implement this interface @Component public class Cake implements Dessert{...} @Component public class Cookies implements Dessert{...} @Component public class IceCream implements Dessert{...}
Spring cannot choose from the three, throwing NoUniqueBeanDefinitionException.
Annotate preferred beans with @Primary annotation
// When configuring beans with @Component, you can annotate @Component with @Primary @Primary public class Cake implements Dessert{...} // When configuring beans with @Bean, you can annotate @Bean with @Primary @Primary public Dessert iceCream{ return new IceCream(); }
<!-- When using XML configuration, set the primary attribute --> < bean id = "iceCream" class = "com.desserteater.IceCream" primary = "true" />
When using @Primary, there will also be multiple matching beans marked with the primary attribute, which will also make Spring unable to choose, resulting in errors
Qualifying assembled beans with the @Qualifier annotation
1. Use default qualifiers
@Autowired @Qualifier("iceCream") public void setDessert(Dessert dessert){ this.dessert = dessert; }
The parameter set by the @Qualifier annotation is the ID of the bean to be injected. If no ID is set for the bean, it is the class name with lowercase first letter (also known as the default qualifier for this bean)
2. Set custom qualifiers for beans
@Component @Qualifier("soft") public class Cake implements Dessert{...} @Bean @Qualifier("cold") public Dessert iceCream{ return new IceCream(); }
Use the @Qualifier annotation on the bean to set a custom qualifier for the bean. Then when autoloading, you can use a custom qualifier to qualify
@Autowired @Qualifier("cold") public void setDessert(Dessert dessert){ this.dessert = dessert; }
3. Use custom qualifier annotations
Suppose that one bean already uses the qualifier cold, and as a result, another bean also needs to use the qualifier cold, so that there will be multiple matching beans and an error will be reported.
The idea to solve this problem is to add qualifiers to these two beans and continue to refine them; however, the @Qualifier annotation does not support repeated annotations, and multiple @Qualifier annotations cannot be used on a bean.
To solve this problem, a custom qualifier annotation can be used:
//代替@Qualifier("cold") @Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface Cold{} //代替@Qualifier("creamy") @Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface Creamy{}
In this way, the following code, the autowiring uses 2 custom qualifier annotations, can also find the only matching bean.
@Bean @Cold @Creamy public Dessert iceCream{ return new IceCream(); } @Bean @Cold public Dessert ice{ return new Ice(); } @Autowired @Cold @Creamy public void setDessert(Dessert dessert){ this.dessert = dessert; }