文章目录
引入
在springboot中,如果一个接口有多个实现,怎么按需注入对应的Bean?
结论
1.@Primary 可指定默认的bean
2.@Resource 默认按照名称注入,找不到会按类型注入【即可能需要匹配两次】,如果name属性一旦指定,就只会按照名称进行装配
3.@Qualifier 按名称注入需要指定名称,配合@Autowired使用
4.@ConditionalOnProperty 按配置统一设定优先注入的Bean
注意
- @Primary不管和下面哪个注解联用,优先级都更低
- @ConditionalOnProperty不能与@Resource、@Qualifier联用,会报错
- @Autowired和@Resource一起使用,@Resource会失效
案例
首先创建了一个MyService接口,提供有一个hello方法:
public interface MyService {
/**
* 说你好
*/
void hello();
}
然后MyServiceAImpl实现接口:
@Service("MyServiceA")
@Slf4j
public class MyServiceAImpl implements MyService {
@Override
public void hello() {
log.info("服务A 说你好帅啊~");
}
}
MyServiceBImpl实现接口:
@Service("MyServiceB")
@Slf4j
public class MyServiceBImpl implements MyService {
@Override
public void hello() {
log.info("服务B 说你好有担当哦~");
}
}
最后我们提供一个单元测试:
@Slf4j
@SpringBootTest(classes = MyWebDemoApplication.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MyServiceDemo {
@Autowired
private MyService myService;
@Test
public void testDemo() {
myService.hello();
}
}
可以看到ida会给出报错信息:
- myService有两个实现,它无法知道要注入哪个?
@Primary 指定默认注入的Bean
使用@Primary注解后,项目默认会注入该Bean,我们给 服务A加上@Primary注解,如下所示,再回到测试类就没有报错了
运行测试类,得到结果能正常输出服务A中的内容:
@Qualifier配合@Autowired 按名称注入对应的Bean
我们不删除服务器A上的@Primary注解,然后测试类中在注入bean的同时添加@Qualifier注解,并指定注入MyServiceB如下图所示:
此时再运行得到结果:
能正常的按Bean的名称注入bean,并且得出结论:@Primary和@Qualifier联用,@Qualifier的优先级更高
@Resource 默认按照字段名,可指定bean名称注入
@Resource就像@Autowired和@Qualifier的整合,默认按照名称注入,找不到会按类型注入【即可能需要匹配两次】,如果name属性一旦指定,就只会按照名称进行装配
回到测试类,我们删除@Autowired和@Qualifier注解,然后添加@Resource注解,并指定对应的bean的名称,如下所示
重新UI运行代码,能得到一样的结果:
**注意:**这里有个小插曲,测试时忘记注释掉@Autowire注解,发现会导致@Resource失效
@ConditionalOnProperty 结合配置文件统一设置bean的注入
场景,比如说我们封装了一套服务接口,里面对应着两套第三方服务的实现,我们希望利用配置文件对整个项目实现统一的服务切换,就可以利用这个注解进行配置。
我们在yaml文件中自定义添加如下配置:
然后分别在serviceA和serviceB中添加注解,并指定符合什么条件时生效:
然后测试类中,我们只留下@Autowired注解,如下图所示:
此时运行就能够按照配置文件进行统一切换啦:
**注意:**亲测@ConditionalOnProperty不能与@Resource、@Qualifier一起使用,会报错