上一篇讲的 @Conditional 可以通过条件控制是否注入 Bean,这篇讲下有关Bean其它几个常用的注解使用方式
@ConditionalOnBean // 当给定的在bean存在时,则实例化当前Bean@ConditionalOnMissingBean // 当给定的在bean不存在时,则实例化当前Bean@ConditionalOnClass // 当给定的类名在类路径上存在,则实例化当前Bean@ConditionalOnMissingClass // 当给定的类名在类路径上不存在,则实例化当前Bean
下面我通过案例深入讲下 @ConditionalOnBean 注解,这个理解其它也就理解了。
一、@ConditionalOnBean 概念
需求场景 比如下面一种场景,我在实例化 People对象的时候,需要注入一个City对象。这个时候问题来了,如果city没有实例化,那么下面就会报空指针或者直接报错。
所以这里需求很简单,就是当前city存在则实例化people,如果不存在则不实例化people,这个时候@ConditionalOnBean 的作用来了。
@Beanpublic 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@NoArgsConstructorpublic class City {/*** 城市名称*/private String cityName;/*** 城市code*/private Integer cityCode;}
2)People类
这里City作为People一个属性字段。
@Data@ToString@NoArgsConstructor@AllArgsConstructorpublic class People {/*** 姓名*/private String name;/*** 年龄*/private Integer age;/*** 城市信息*/private City city;}
2、Config 类
这里写个正常的配置类,City 成功注入到 IOC 容器中。
@Slf4j@Configurationpublic class Config {@Beanpublic City city() {City city = new City();city.setCityName("千岛湖");return city;}@Beanpublic 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;@Testpublic 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@Configurationpublic 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
