@ConditionalOnMissingBean与@ConditionalOnBean

俩个作用:根据当前环境或者容器情况来动态注入bean,要配合@Bean使用
@ConditionalOnMissingBean作用:判断当前需要注入Spring容器中的bean的实现类是否已经含有,有的话不注入,没有就注入
@ConditionalOnBean作用:判断当前需要注册的bean的实现类否被spring管理,如果被管理则注入,反之不注入

源码:

@ConditionalOnMissingBean和@ConditionalOnBean

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnBeanCondition.class})
public @interface ConditionalOnBean {
    Class<?>[] value() default {};

    String[] type() default {};

    Class<? extends Annotation>[] annotation() default {};

    String[] name() default {};

    SearchStrategy search() default SearchStrategy.ALL;// bean工厂层次结构中bean的一些命名搜索策略

    Class<?>[] parameterizedContainer() default {};
}

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnBeanCondition.class})
public @interface ConditionalOnMissingBean {
    Class<?>[] value() default {};

    String[] type() default {};

    Class<?>[] ignored() default {};

    String[] ignoredType() default {};

    Class<? extends Annotation>[] annotation() default {};

    String[] name() default {};

    SearchStrategy search() default SearchStrategy.ALL;

    Class<?>[] parameterizedContainer() default {};
}

可以发现@ConditionalOnMissingBean@ConditionalOnBean俩个注解的动态注入条件判断类都是OnBeanCondition,并且都是基于@Conditional注解。

@Conditional具体可以去看 @Conditional注解使用与自定义验证注解 这篇文章

OnBeanCondition:

@Order(2147483647)
class OnBeanCondition extends FilteringSpringBootCondition implements ConfigurationCondition {
	...具体内容可以看代码
}

OnBeanCondition没有直接实现matches方法,而是使用的FilteringSpringBootCondition的父类SpringBootCondition类中的matches方法。

demo:

  • 创建接口Animal

    public interface Animal {
        String eat();
    }
    
  • 分别创建俩个实现类

    public class Dog implements Animal {
        @Override
        public String eat() {
            return "肉";
        }
    }
    
    public class Cat implements Animal {
        @Override
        public String eat() {
            return "老鼠";
        }
    }
    
  • 创建俩个配置类

    @Configuration
    public class CatConfig {
        @Bean
        public Animal animal() {
            return new Cat();
        }
    }
    
    @Configuration
    public class DogConfig {
        @Bean
        public Animal animal() {
            return new Cat();
        }
    }
    
  • 测试类

    @SpringBootApplication
    public class ServiceDiscoverApplication implements CommandLineRunner {
    
        @Autowired
        private Animal animal;
    
        public static void main(String[] args) {
            SpringApplication.run(ServiceDiscoverApplication.class, args);
        }
    
    	//测试方法
        @Override
        public void run(String... args) throws Exception {
            String eat = animal.eat();
            System.out.println(eat);
        }
    }
    
  • 测试

    • @ConditionalOnMissingBean

      修改配置类,在CatConfig中添加@ConditionalOnMissingBean注解

    @Configuration
    public class CatConfig {
        @Bean
        @ConditionalOnMissingBean
        public Animal animal() {
            return new Cat();
        }
    }
    
    运行程序:控制台输出为 '肉' 当在DogConfig中添加@ConditionalOnMissingBean注解,运行结果为 '老鼠'
        
    如果当前容器中含有Animal类型的bean,那么就不加载带有@ConditionalOnMissingBean注解的Animal类型bean到spring的ioc容器。
    
    • @ConditionalOnBean

      修改Cat类,去掉@Service,不让spring管理

      public class Cat implements Animal {
          @Override
          public String eat() {
              return "老鼠";
          }
      }
      

      修改CatConfig类,在CatConfig中添加@ConditionalOnBean注解

      @Configuration
      public class CatConfig {
          @Bean
          @ConditionalOnBean(Cat.class)
          public Animal animal() {
              return new Cat();
          }
      }
      运行程序:控制台输出为 '肉' 当在DogConfig中添加@ConditionalOnBean(Dog.class)注解、去掉@Service注解时,运行结果为 '老鼠'
          
      
      当bean Animal的实现类没有被spring所管理,那么就不会加载带有@ConditionalOnBean注解的bean到spring的ioc容器。
      
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐