Spring注解@Qualifier和@Primary详细解析
1. 概述
今天带你了解⼀下 Spring 框架中的 @Qualifier 注解,它解决了哪些问题,以及如何使⽤它。我们还将了解它与 @Primary 注解的不同之处。
2. 痛点
使⽤ @Autowired 注解是 Spring 依赖注⼊的绝好⽅法。但是有些场景下仅仅靠这个注解不⾜以让Spring知道到底要注⼊哪个 bean。默认情况下,@Autowired 按类型装配 Spring Bean。如果容器中有多个相同类型的 bean,则框架将抛
出 NoUniqueBeanDefinitionException, 以提⽰有多个满⾜条件的 bean 进⾏⾃动装配。程序⽆法正确做出判断使⽤哪⼀个,下⾯就是个鲜活的例⼦:
@Component("fooFormatter")
public class FooFormatter implements Formatter {
public String format() {
return "foo";
}
}
@Component("barFormatter")
public class BarFormatter implements Formatter {
public String format() {
return "bar";
}
}
@Component
public class FooService {
@Autowired
private Formatter formatter;
//todo
}
如果我们尝试将 FooService 加载到我们的上下⽂中,Spring 框架将抛出 NoUniqueBeanDefinitionException。这是因为 Spring 不知道要注⼊哪个 bean。为了避免这个问题,有⼏种解决⽅案。那么我们本⽂要讲解的 @Qualifier 注解就是其中之⼀。
3. @Qualifier
通过使⽤ @Qualifier 注解,我们可以消除需要注⼊哪个 bean 的问题。让我们重新回顾⼀下前⾯的例
⼦,看看我们如何通过包
含 @Qualifier 注释来指出我们想要使⽤哪个 bean 来解决问题:
@Component
public class FooService {
@Autowired
@Qualifier("fooFormatter")
private Formatter formatter;
//todo
}
通过将 @Qualifier 注解与我们想要使⽤的特定 Spring bean 的名称⼀起进⾏装配,Spring 框架就能从多个相同类型并满⾜装配要求
的 bean 中到我们想要的,避免让Spring脑裂。我们需要做的是@Component或者@Bean注解中声明的value属性以确定名称。其实我们也可以在 Formatter 实现类上使⽤ @Qualifier 注释,⽽不是在 @Component 或者 @Bean 中指定名称,也能达到相同的效果:
@Component
// 指明bean名称
@Qualifier("fooFormatter")
public class FooFormatter implements Formatter {
public String format() {
return "foo";
}
}
@Component
// 指明bean名称
@Qualifier("barFormatter")
public class BarFormatter implements Formatter {
public String format() {
return "bar";
}
}
@Component
public class FooService {
@Autowired
// 同样使⽤@Qualifier进⾏指明注⼊
@Qualifier("fooFormatter")
private Formatter formatter;
//todo
}
4. @Qualifier VS @Primary
还有另⼀个名为 @Primary 的注解,我们也可以⽤来发⽣依赖注⼊的歧义时决定要注⼊哪个 bean。当存在多个相同类型的 bean 时,此注解定义了⾸选项。除⾮另有说明,否则将使⽤与 @Primary 注释关联的 bean 。
我们来看⼀个例⼦:
@Bean
public Employee tomEmployee() {
return new Employee("Tom");
}
@Bean
@Primary
public Employee johnEmployee() {
return new Employee("john");
}
@Component
public class Job1 {
// 注⼊的是john Employee,因为它有@Primary注解
@Autowired
private Employee employee;
/
/ TODO
}
在此⽰例中,两个⽅法都返回相同的 Employee类型。Spring 将注⼊的 bean 是⽅法 john Employee 返回的 bean。这是因为它包
含 @Primary 注解。当我们想要指定默认情况下应该注⼊特定类型的 bean 时,此注解很有⽤。如果我们在某个注⼊点需要另⼀个 bean,我们需要专门指出它。我们可以通过 @Qualifier 注解来做到这⼀点。例如,我们可以通过使⽤ @Qualifier 注释来指定我们想要使
⽤ tomEmployee ⽅法返回的 bean 。值得注意的是,如果 @Qualifier 和 @Primary 注释都存在,那么 @Qualifier 注释将具有优先权。基本上,@Primary 是定义了默认值,⽽ @Qualifier 则⾮常具体。当然 @Component 也可以使⽤ @Primary 注解,这次使⽤的还是上⾯3的⽰例:
@Component
@Primary
public class FooFormatter implements Formatter {
public String format() {
return "foo";
}
}
spring系列框架有哪些@Component
public class BarFormatter implements Formatter {
public String format() {
return "bar";
}
}
@Component
public class Job1 {
// 注⼊的是FooFormatter,因为它有@Primary注解
@Autowired
private Formatter formatter;
// TODO
}
在这种情况下,@Primary 注解指定了默认注⼊的是 FooFormatter,消除了场景中的注⼊歧义。
5. 通过名称来⾃动注⼊
在使⽤ @Autowired 进⾏⾃动装配时,如果 Spring 没有其他提⽰,将会按照需要注⼊的变量名称来寻合适的 bean。也可以解决依赖注⼊歧义的问题。让我们看⼀些基于我们最初的例⼦的代码:
@Component
public class FooFormatter implements Formatter {
public String format() {
return "foo";
}
}
@Component
public class BarFormatter implements Formatter {
public String format() {
return "bar";
}
}
@Component
public class Job1 {
// 虽然没⽤使⽤@Primary,但注⼊的是FooFormatter,因为变量名就是beanName
// beanName默认就是类名的驼峰命名
@Autowired
private Formatter fooFormatter;
// TODO
}
在这种情况下,Spring 将确定要注⼊的 bean 是 FooFormatter,因为字段名称与我们在该 bean 的 @Component或者 @Bean 注解中使⽤的值(默认 @Bean 使⽤⽅法名)相匹配。
6. 总结
通过对 @Qualifier 的探讨,我们知道该注解是⽤来消除依赖注⼊冲突的。这种可以解决在⽇常开发中,经常遇到的⼀个接⼝多个实现类的注⼊问题。这将有助于你对 Spring 的依赖注⼊机制的了解。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论