@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