上一篇讲的 @Conditional 可以通过条件控制是否注入 Bean,这篇讲下有关Bean其它几个常用的注解使用方式

  1. @ConditionalOnBean // 当给定的在bean存在时,则实例化当前Bean
  2. @ConditionalOnMissingBean // 当给定的在bean不存在时,则实例化当前Bean
  3. @ConditionalOnClass // 当给定的类名在类路径上存在,则实例化当前Bean
  4. @ConditionalOnMissingClass // 当给定的类名在类路径上不存在,则实例化当前Bean

下面我通过案例深入讲下 @ConditionalOnBean 注解,这个理解其它也就理解了。

一、@ConditionalOnBean 概念

需求场景 比如下面一种场景,我在实例化 People对象的时候,需要注入一个City对象。这个时候问题来了,如果city没有实例化,那么下面就会报空指针或者直接报错。
所以这里需求很简单,就是当前city存在则实例化people,如果不存在则不实例化people,这个时候@ConditionalOnBean 的作用来了。

  1. @Bean
  2. public People people(City city) {
  3. //这里如果city实体没有成功注入 这里就会报空指针
  4. city.setCityName("千岛湖");
  5. city.setCityCode(301701);
  6. return new People("小小", 3, city);
  7. }

1、@ConditionalOnBean 注解定义

  1. @Target({ ElementType.TYPE, ElementType.METHOD })
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Conditional(OnBeanCondition.class)
  5. public @interface ConditionalOnBean {
  6. /**
  7. * 需要作为条件的类的Class对象数组
  8. */
  9. Class<?>[] value() default {};
  10. /**
  11. * 需要作为条件的类的Name,Class.getName()
  12. */
  13. String[] type() default {};
  14. /**
  15. * (用指定注解修饰的bean)条件所需的注解类
  16. */
  17. Class<? extends Annotation>[] annotation() default {};
  18. /**
  19. * spring容器中bean的名字
  20. */
  21. String[] name() default {};
  22. /**
  23. * 搜索容器层级,当前容器,父容器
  24. */
  25. SearchStrategy search() default SearchStrategy.ALL;
  26. /**
  27. * 可能在其泛型参数中包含指定bean类型的其他类
  28. */
  29. Class<?>[] parameterizedContainer() default {};
  30. }

下面举例说明。

二、@ConditionalOnBean 示例

1、Bean 实体

1)City 类

  1. @Data
  2. @ToString
  3. @AllArgsConstructor
  4. @NoArgsConstructor
  5. public class City {
  6. /**
  7. * 城市名称
  8. */
  9. private String cityName;
  10. /**
  11. * 城市code
  12. */
  13. private Integer cityCode;
  14. }

2)People类
这里City作为People一个属性字段。

  1. @Data
  2. @ToString
  3. @NoArgsConstructor
  4. @AllArgsConstructor
  5. public class People {
  6. /**
  7. * 姓名
  8. */
  9. private String name;
  10. /**
  11. * 年龄
  12. */
  13. private Integer age;
  14. /**
  15. * 城市信息
  16. */
  17. private City city;
  18. }

2、Config 类

这里写个正常的配置类,City 成功注入到 IOC 容器中。

  1. @Slf4j
  2. @Configuration
  3. public class Config {
  4. @Bean
  5. public City city() {
  6. City city = new City();
  7. city.setCityName("千岛湖");
  8. return city;
  9. }
  10. @Bean
  11. public People people(City city) {
  12. //这里如果city实体没有成功注入 这里就会报空指针
  13. city.setCityCode(301701);
  14. return new People("小小", 3, city);
  15. }
  16. }

3、Test测试类

  1. @SpringBootTest(classes = Application.class)
  2. @RunWith(SpringRunner.class)
  3. public class TestConditionOn {
  4. @Autowired(required=false)
  5. private People people;
  6. @Test
  7. public void test() {
  8. System.out.println("= = = = = = = = = = = = = ");
  9. System.out.println("people = " + people);
  10. System.out.println("= = = = = = = = = = = = = ");
  11. }
  12. }

运行结果
02 @ConditionalOnBean 与 @ConditionalOnClass - 图1
一切正常,这个很符合我们实际开发中的需求。但是如果有一种情况,就是我的city并没有被注入。我把上面这部分注视掉。

  1. // @Bean
  2. // public City city() {
  3. // City city = new City();
  4. // city.setCityName("千岛湖");
  5. // return city;
  6. // }

再运行测试类
02 @ConditionalOnBean 与 @ConditionalOnClass - 图2
发现启动直接报错了,这当然不是我们希望看到的,我们是要当city已经注入那么实例化people,如果没有注入那么不实例化 people。

  1. @Slf4j
  2. @Configuration
  3. public class Config {
  4. // @Bean
  5. // public City city() {
  6. // City city = new City();
  7. // city.setCityName("千岛湖");
  8. // return city;
  9. // }
  10. /**
  11. * 这里加了ConditionalOnBean注解,就代表如果city存在才实例化people
  12. */
  13. @Bean
  14. @ConditionalOnBean(name = "city")
  15. public People people(City city) {
  16. //这里如果city实体没有成功注入 这里就会报空指针
  17. city.setCityCode(301701);
  18. return new People("小小", 3, city);
  19. }
  20. }

再运行测试类
02 @ConditionalOnBean 与 @ConditionalOnClass - 图3
很明显,上面因为city已经注释调,所以也导致无法实例化people,所以 people 为 null。
注意有点要注意的,就是一旦使用 @Autowired 那就默认代表当前Bean一定是已经存在的,如果为 null,会报错。所以这里要修改下。

  1. @Autowired(required=false) //required=false 的意思就是允许当前的Bean对象为null。

总结讲了这个注解,其它三个注解的意思大致差不多,在实际开发过程中可以根据实际情况使用该注解。
GitHub源码 https://github.com/yudiandemingzi/spring-boot-study
项目名称 04-conditionalon