@Qualifier
高级使用
@Autowired
是根据类型进行自动装配的,当Spring容器内同一类型的Bean不止一个的时候,就需要借助@Qualifier
来一起使用了。
示例一:
@Configuration public class WebMvcConfiguration { @Qualifier("person1") @Autowired public Person person; @Bean public Person person1() { return new Person("fsx01", 16); } @Bean public Person person2() { return new Person("fsx02", 18); } }
单测代码如下(下同):
public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(WebMvcConfiguration.class); WebMvcConfiguration bean = context.getBean(WebMvcConfiguration.class); // 打印字段的值 System.out.println(bean.person); }
运行后打印Person(name=fsx01, age=16),完全符合预期。这也是我们对@Qualifier注解最常规、最简单的使用。
示例二:
若你细心的话你可能注意到了@Qualifier注解它允许继承(@Inherited)、能标注在字段上、方法上、方法参数、类上、注解上。
因此它还能这么用:
@Configuration public class WebMvcConfiguration { @MyAnno // 会把所有标注有此注解的Bean都收入囊中,请List装(因为会有多个) @Autowired public List<Person> person; @MyAnno @Bean public Person person1() { return new Person("fsx01", 16); } @MyAnno @Bean public Person person2() { return new Person("fsx02", 18); } // 自定义注解:上面标注有@Qualifier注解 @Target({FIELD, METHOD}) @Retention(RetentionPolicy.RUNTIME) @Qualifier @interface MyAnno { } }
运行单测,打印[Person(name=fsx01, age=16), Person(name=fsx02, age=18)]
,符合预期。
若你不想自定义注解,直接使用@Qualifier
注解分类注入也是可以的,如下案例:
@Configuration public class WebMvcConfiguration { @Qualifier("person2") @Autowired public List<Person> person; @Qualifier("person2") @Bean public Person person1() { return new Person("fsx01", 16); } @Qualifier @Bean public Person person2() { return new Person("fsx02", 18); } @Qualifier @Bean public Person person3() { return new Person("fsx03", 20); } }
运行的最终结果是:
[Person(name=fsx01, age=16), Person(name=fsx02, age=18)]
它把@Qualifier指定的value值相同的 或者 beanName(或者别名)相同的都注入进来了。这部分匹配代码为
checkQualifier方法: 1、头上标注的注解完全equals(类型和value值都一样,算作匹配成功) targetAnnotation != null && targetAnnotation.equals(annotation) 2、Fall back on bean name (or alias) match。若@Qualifier没匹配上,回退到BeanName的匹配,规则为: 取头上注解的`value`属性(必须有此属性),如果beanName/alias能匹配上次名称,也算最终匹配成功了 actualValue == null && attributeName.equals(AutowireCandidateQualifier.VALUE_KEY) && expectedValue instanceof String && bdHolder.matchesName((String) expectedValue)
备注:使用在类上、入参上的使用比较简单,此处就不做示范了。
从@Qualifier设计的细节可以看到,注解的value属性并不是必须的,所以它可以很好的使用在联合注解的场景。
关于依赖注入和@Qualifier的使用亦需注意如下细节:
- @Autowired可不要写在Object类型的字段上去注入,因为容器内可以找到N多个会报错的。但是List<Object>是可以的(相当于把所有Bean都拿过来~)
- 可以利用@Qualifier这个高级特性,实现按需、按类别(不是类型)进行依赖注入,这种能力非常赞,给了框架二次开发设计者提供了更多的可能性
如果说指定value是按照key进行限定/匹配,那么类似@LoadBalanced这种注解匹配可以理解成就是按照莫一类进行归类限定了,并且自由度也更高了。
推荐阅读
为何一个@LoadBalanced注解就能让RestTemplate拥有负载均衡的能力?【享学Spring Cloud】
总结
本文介绍@Qualifier高级应用场景和案例,通过结合@LoadBalanced对此注解的使用,应该说是能给你打开了一个新的视角去看待@Qualifier,甚至看待Spring的依赖注入,这对后续的理解、自定义扩展/使用还是蛮有意义的。