• 【转】 SpringBoot(16)—@ConditionalOnBean与@ConditionalOnClass


    【转】 SpringBoot(16)—@ConditionalOnBean与@ConditionalOnClass

    @ConditionalOnBean与@ConditionalOnClass

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

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

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

    一、@ConditionalOnBean概念

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

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

    1、@ConditionalOnBean注解定义

    @Target({ ElementType.TYPE, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Conditional(OnBeanCondition.class)
    public @interface ConditionalOnBean {
        /**
         * 需要作为条件的类的Class对象数组
         */
        Class<?>[] value() default {};
        /**
         * 需要作为条件的类的Name,Class.getName()
         */
        String[] type() default {};
        /**
         *  (用指定注解修饰的bean)条件所需的注解类
         */
        Class<? extends Annotation>[] annotation() default {};
        /**
         * spring容器中bean的名字
         */
        String[] name() default {};
        /**
         * 搜索容器层级,当前容器,父容器
         */
        SearchStrategy search() default SearchStrategy.ALL;
        /**
         * 可能在其泛型参数中包含指定bean类型的其他类
         */
        Class<?>[] parameterizedContainer() default {};
    }
    

    下面举例说明。

    二、@ConditionalOnBean示例

    1、Bean实体

    1)City类

    @Data
    @ToString
    @AllArgsConstructor
    @NoArgsConstructor
    public class City {
        /**
         * 城市名称
         */
        private String cityName;
        /**
         * 城市code
         */
        private Integer cityCode;
    }
    

    2)People类

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

    @Data
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    public class People {
      /**
         * 姓名
         */
        private String name;
        /**
         * 年龄
         */
        private Integer age;
        /**
         *  城市信息
         */
        private City city;
    }
    

    2、Config类

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

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

    3、Test测试类

    @SpringBootTest(classes = Application.class)
    @RunWith(SpringRunner.class)
    public class TestConditionOn {
    
        @Autowired(required=false)
        private People people;
        
        @Test
        public void test() {
            System.out.println("= = = = = = = = = = = = = ");
            System.out.println("people = " + people);
            System.out.println("= = = = = = = = = = = = = ");
        }
    }
    

    运行结果

    一切正常,这个很符合我们实际开发中的需求。但是如果有一种情况,就是我的city并没有被注入。我把上面这部分注视掉。

    //    @Bean
    //    public City city() {
    //        City city = new City();
    //        city.setCityName("千岛湖");
    //        return city;
    //    }
    

    再运行测试类

    发现启动直接报错了,这当然不是我们希望看到的,我们是要当city已经注入那么实例化people,如果没有注入那么不实例化people。

    @Slf4j
    @Configuration
    public class Config {
    //    @Bean
    //    public City city() {
    //        City city = new City();
    //        city.setCityName("千岛湖");
    //        return city;
    //    }
    
        /**
         * 这里加了ConditionalOnBean注解,就代表如果city存在才实例化people
         */
        @Bean
        @ConditionalOnBean(name = "city")
        public People people(City city) {
            //这里如果city实体没有成功注入 这里就会报空指针
            city.setCityCode(301701);
            return new People("小小", 3, city);
        }
    }
    

    再运行测试类

    很明显,上面因为city已经注释调,所以也导致无法实例化people,所以people为null。

    注意有点要注意的,就是一旦使用@Autowired那就默认代表当前Bean一定是已经存在的,如果为null,会报错。所以这里要修改下。

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

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


    只要自己变优秀了,其他的事情才会跟着好起来(中将4)
    
  • 相关阅读:
    CSP2020 游记
    关于对拍
    联考day7
    CSP 模拟26
    动态规划
    JAVA单元测试的用法和要点(入门篇)
    乐观锁和悲观锁的区别
    并发基础篇(六):线程Thread类的start()方法和run()方法【转载】
    this和super差异
    Java中的static关键字解析
  • 原文地址:https://www.cnblogs.com/Javastudy-note/p/13818106.html
Copyright © 2020-2023  润新知