springboot @ConditionalOnMissing
@ConditionalOnMissingBean与@ConditionalOnBean
俩个作用:根据当前环境或者容器情况来动态注入bean,要配合@Bean使用
@ConditionalOnMissingBean作用:判断当前需要注入Spring容器中的bean的实现类是否已经含有,有的话不注入,没有就注入
@ConditionalOnBean作用:判断当前需要注册的bean的实现类否被spring管理,如果被管理则注入,反之不注入
@ConditionalOnMissingBean,它是修饰bean的一个注解,主要实现的是,当你的bean被注册之后,如果而注册相同类型的bean,就不会成功,它会保证你的bean只有一个,即你的实例只有一个,当你注册多个相同的bean时,会出现异常,以此来告诉开发人员。
@Component
public class AutoConfig {
@Bean
public AConfig aConfig() {
return new AConfig("lind");
}
@Bean
@ConditionalOnMissingBean(AMapper.class)
public AMapper aMapper1(AConfig aConfig) {
return new AMapperImpl1(aConfig);
}
@Bean
public AMapper aMapper2(AConfig aConfig) {
return new AMapperImpl2(aConfig);
}
}
因为在aMapper1上面标识了AMapper类型的bean只能有一个实现 @ConditionalOnMissingBean(AMapper.class),所以在进行aMapper2注册时,系统会出现上面图上的异常,这是正常的。
当我们把 @ConditionalOnMissingBean(AMapper.class) 去掉之后,你的bean可以注册多次,这时需要用的@Primary来确定你要哪个实现;一般来说,对于自定义的配置类,我们应该加上@ConditionalOnMissingBean注解,以避免多个配置同时注入的风险。
@Primary标识哪个是默认的bean
@Bean
public AMapper aMapper1(AConfig aConfig) {
return new AMapperImpl1(aConfig);
}
@Bean
@Primary
public AMapper aMapper2(AConfig aConfig) {
return new AMapperImpl2(aConfig);
}
另一个案例
程序入口:ConditionalDemoApplication:
@SpringBootApplication
public class ConditionalDemoApplication implements CommandLineRunner {
@Autowired
private Van van;
public static void main(String[] args) {
SpringApplication.run(ConditionalDemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception{
van.fight();
}
}
Van.java
@Service
public class Van {
@Autowired
private Fighter fighter;
public void fight(){
System.out.println("van:boy next door,do you like 玩游戏");
fighter.fight();
}
}
Fighter.java及其实现类:
public interface Fighter {
void fight();
}
@Service
public class Babana implements Fighter {
@Override
public void fight(){
System.out.println("Banana: 自由的气息,蕉迟但到");
}
}
@Service
public class Billy implements Fighter {
public void fight(){
System.out.println("Billy:吾乃新日暮里的王,三界哲学的主宰。");
}
}
VanConfig:
@Configuration
public class VanConfig {
@Bean
@ConditionalOnBean(Billy.class)
public Fighter fighter(){
return new Billy();
}
@Bean
@ConditionalOnMissingBean
public Fighter fighter2(){
return new Babana();
}
}
1、运行程序,输入结果如下:
Billy:吾乃新日暮里的王,三界哲学的主宰。
2、如果将Billy Bean的代码注释掉:
@Configuration
public class VanConfig {
/*@Bean
@ConditionalOnBean(Billy.class)
public Fighter fighter(){
return new Billy();
}*/
@Bean
@ConditionalOnMissingBean
public Fighter fighter2(){
return new Babana();
}
}
重新运行,输入结果如下:
Banana: 自由的气息,蕉迟但到
3、或者,我们将Billy上的@Service注解注释掉,让springboot扫描不到该类:
//@Service
public class Billy implements Fighter {
public void fight(){
System.out.println("Billy:吾乃新日暮里的王,三界哲学的主宰。");
}
}
同时恢复VanConfig里的配置:
@Configuration
public class VanConfig {
@Bean
@ConditionalOnBean(Billy.class)
public Fighter fighter(){
return new Billy();
}
@Bean
@ConditionalOnMissingBean
public Fighter fighter2(){
return new Babana();
}
}
再次运行,输入结果如下(与第2次试验的效果相同):
场景实例:
Service 层,通过@ConditionalOnProperty 判断,然后结合@ConditionalOnMissingBean(xx.class) 做只能生效一个service