@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)