日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

SpringBoot基础篇Bean之条件注入之注解使用

發(fā)布時間:2023/12/20 javascript 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringBoot基础篇Bean之条件注入之注解使用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

bean的條件注入,除了前面一篇博文中介紹的通過@Conditional注解配合Condition接口的實現(xiàn)之外,還提供了更多簡化的注解使用方式,省略了自己實現(xiàn)Condtion接口,本篇博文主要介紹下面幾個常用的注解使用方式

  • @ConditionalOnBean
  • @ConditionalOnMissingBean
  • @ConditionalOnClass
  • @ConditionalOnMissingClass
  • @ConditionalOnProperty
  • @ConditionalOnExpression

I. Bean的存在與否作為條件

當(dāng)Bean不存在時,創(chuàng)建一個默認的Bean,在Spring的生態(tài)中可以說比較常見了;接下來看下這種方式可以怎么用

1. @ConditionalOnBean

要求bean存在時,才會創(chuàng)建這個bean;如我提供了一個bean名為RedisOperBean,用于封裝redis相關(guān)的操作;但是我這個bean需要依賴restTemplate這個bean,只有當(dāng)應(yīng)用引入了redis的相關(guān)依賴,并存在RestTemplate這個bean的時候,我這個bean才會生效

假設(shè)bean的定義如下

@Component @ConditionalOnBean(name="redisTemplate") public class RedisOperBean {private final RedisTemplate redisTemplate;public RedisOperBean(RedisTemplate redisTemplate) {// ...} } 復(fù)制代碼

這樣的好處就是我提供的這個第三方包,如果被用戶A間接依賴(但是A本身不需要操作redis),也不會因為創(chuàng)建RedisOperBean而拋異常

產(chǎn)生異常的原因是因為找不到RestTemplate的bean,因此無法實例化RedisOperBean,從而拋出異常

a. 注解定義

@Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional(OnBeanCondition.class) public @interface ConditionalOnBean {// bean類型Class<?>[] value() default {};// bean類型String[] type() default {};// 要求bean上擁有指定的注解Class<? extends Annotation>[] annotation() default {};// bean namesString[] name() default {};SearchStrategy search() default SearchStrategy.ALL; } 復(fù)制代碼

b. 測試用例

構(gòu)建一個簡單的測試用例,先定義一個基礎(chǔ)的bean

public class DependedBean { } 復(fù)制代碼

再定義一個依賴只有上面的bean存在時,才會加載的bean

public class LoadIfBeanExist {private String name;public LoadIfBeanExist(String name) {this.name = name;}public String getName() {return "load if bean exists: " + name;} } 復(fù)制代碼

接下來就是bean的定義了

@Bean public DependedBean dependedBean() {return new DependedBean(); }/*** 只有當(dāng)DependedBean 存在時,才會創(chuàng)建bean: `LoadIfBeanExist`** @return*/ @Bean @ConditionalOnBean(name = "dependedBean") public LoadIfBeanExist loadIfBeanExist() {return new LoadIfBeanExist("dependedBean"); } 復(fù)制代碼

根據(jù)上面的測試用例,LoadIfBeanExist是會被正常加載的; 具體結(jié)果看后面的實例演示

2. ConditionalOnMissingBean

和前面一個作用正好相反的,上面是要求存在bean,而這個是要求不存在

a. 接口定義

public @interface ConditionalOnMissingBean {Class<?>[] value() default {};String[] type() default {};/*** The class type of beans that should be ignored when identifying matching beans.*/Class<?>[] ignored() default {};/*** The class type names of beans that should be ignored when identifying matching* beans.*/String[] ignoredType() default {};Class<? extends Annotation>[] annotation() default {};String[] name() default {};SearchStrategy search() default SearchStrategy.ALL; } 復(fù)制代碼

b. 測試用例

同樣定義一個bean不存在時,才創(chuàng)建的bean

public class LoadIfBeanNotExists {public String name;public LoadIfBeanNotExists(String name) {this.name = name;}public String getName() {return "load if bean not exists: " + name;} } 復(fù)制代碼

對應(yīng)的bean配置如下

/*** 只有當(dāng)沒有notExistsBean時,才會創(chuàng)建bean: `LoadIfBeanNotExists`** @return*/ @Bean @ConditionalOnMissingBean(name = "notExistsBean") public LoadIfBeanNotExists loadIfBeanNotExists() {return new LoadIfBeanNotExists("notExistsBean"); } 復(fù)制代碼

因為沒有notExistsBean,所以上面這個bean也應(yīng)該被正常注冊

3. 實例演示

因為bean的是否存在和class的是否存在有較大的相似性,因此實例演示放在下一小節(jié),一起測試

II. Class的存在與否作為條件

從使用來看,和前面基本上沒有太大的區(qū)別,無非就是將bean換成了class;這樣就可以避免因為Class Not Found導(dǎo)致的編譯異常了

1. @ConditionalOnClass

要求class存在

a. 注解定義

public @interface ConditionalOnClass {Class<?>[] value() default {};/*** The classes names that must be present.* @return the class names that must be present.*/String[] name() default {};} 復(fù)制代碼

b. 測試用例

先定義一個class

public class DependedClz { } 復(fù)制代碼

然后依賴class存在的bean

public class LoadIfClzExists {private String name;public LoadIfClzExists(String name) {this.name = name;}public String getName() {return "load if exists clz: " + name;} } 復(fù)制代碼

接下來就是Bean的配置

/*** 當(dāng)引用了 {@link DependedClz} 類之后,才會創(chuàng)建bean: `LoadIfClzExists`** @return*/ @Bean @ConditionalOnClass(DependedClz.class) public LoadIfClzExists loadIfClzExists() {return new LoadIfClzExists("dependedClz"); } 復(fù)制代碼

因為類存在,所以測試時,這個bean應(yīng)該被正常注冊

2. @ConditionalOnMissingClass

class不存在時,才會加載bean

a. 注解定義

public @interface ConditionalOnMissingClass {String[] value() default {}; } 復(fù)制代碼

b. 測試用例

定義一個class缺少時才會創(chuàng)建的bean

public class LoadIfClzNotExists {private String name;public LoadIfClzNotExists(String name) {this.name = name;}public String getName() {return "load if not exists clz: " + name;} } 復(fù)制代碼

bean的配置如下

/*** 當(dāng)系統(tǒng)中沒有 com.git.hui.boot.conditionbean.example.depends.clz.DependedClz類時,才會創(chuàng)建這個bean** @return*/ @Bean @ConditionalOnMissingClass("com.git.hui.boot.conditionbean.example.depends.clz.DependedClz") public LoadIfClzNotExists loadIfClzNotExists() {return new LoadIfClzNotExists("com.git.hui.boot.conditionbean.example.depends.clz.DependedClz"); } 復(fù)制代碼

因為上面這個類存在,所以這個bean不應(yīng)該被正常注冊

3. 實例演示

起一個rest服務(wù),測試下上面的四個bean是否正常

@RestController @RequestMapping("depends") public class DependRest {@Autowiredprivate LoadIfBeanExist loadIfBeanExist;@Autowiredprivate LoadIfBeanNotExists loadIfBeanNotExists;@Autowiredprivate LoadIfClzExists loadIfClzExists;@Autowired(required = false)private LoadIfClzNotExists loadIfClzNotExists;@GetMapping(path = "show")public String show() {Map<String, String> result = new HashMap<>(4);// 存在result.put("loadIfBeanExist", loadIfBeanExist == null ? "null ==> false!" : loadIfBeanExist.getName());// 存在result.put("loadIfBeanNotExists",loadIfBeanNotExists == null ? "null ==> false!" : loadIfBeanNotExists.getName());// 存在result.put("loadIfClzExists", loadIfClzExists == null ? "null ==> false!" : loadIfClzExists.getName());// 不存在result.put("loadIfClzNotExists", loadIfClzNotExists == null ? "null ==> true!" : loadIfClzNotExists.getName());return JSONObject.toJSONString(result);} } 復(fù)制代碼

根據(jù)前面的分析,返回的結(jié)果應(yīng)該是三個存在,一個不存在;下圖執(zhí)行和我們預(yù)期一致

III. 配置屬性作為條件

主要是根據(jù)配置參數(shù),來決定是否需要創(chuàng)建這個bean,這樣就給了我們一個根據(jù)配置來控制Bean的選擇的手段了,如前面一篇博文中根據(jù)配置來選擇是隨機生成boolean還是隨機生成int;只需要更改配置即可

1. @ConditionalOnProperty

@Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE, ElementType.METHOD }) @Documented @Conditional(OnPropertyCondition.class) public @interface ConditionalOnProperty {/*** Alias for {@link #name()}.* @return the names*/String[] value() default {};// 配置前綴String prefix() default "";// 配置名String[] name() default {};// 要求配置存在,且包含某個值String havingValue() default "";// 即便沒有配置,也依然創(chuàng)建boolean matchIfMissing() default false; } 復(fù)制代碼

2. 實例測試

a. 測試用例

測試幾個常用的姿勢,一是根據(jù)配置是否存在,來決定是否創(chuàng)建

public class PropertyExistBean {private String name;public PropertyExistBean(String name) {this.name = name;}public String getName() {return "property : " + name;} }public class PropertyNotExistBean {private String name;public PropertyNotExistBean(String name) {this.name = name;}public String getName() {return "no property" + name;} } 復(fù)制代碼

對應(yīng)的bean配置如下

/*** 配置存在時才會加載這個bean** @return*/ @Bean @ConditionalOnProperty("conditional.property") public PropertyExistBean propertyExistBean() {return new PropertyExistBean(environment.getProperty("conditional.property")); }/*** 即便配置不存在時,也可以加載這個bean** @return*/ @Bean @ConditionalOnProperty(name = "conditional.property.no", matchIfMissing = true) public PropertyNotExistBean propertyNotExistBean() {return new PropertyNotExistBean("conditional.property"); } 復(fù)制代碼

當(dāng)配置存在,且value匹配時

public class PropertyValueExistBean {public String name;public PropertyValueExistBean(String name) {this.name = name;}public String getName() {return "property value exist: " + name;} }public class PropertyValueNotExistBean {public String name;public PropertyValueNotExistBean(String name) {this.name = name;}public String getName() {return "property value not exist: " + name;} } 復(fù)制代碼

對應(yīng)的配置如下

@Bean @ConditionalOnProperty(name = {"conditional.property"}, havingValue = "properExists") public PropertyValueExistBean propertyValueExistBean() {return new PropertyValueExistBean("properExists"); }@Bean @ConditionalOnProperty(name = {"conditional.property"}, havingValue = "properNotExists") public PropertyValueNotExistBean propertyValueNotExistBean() {return new PropertyValueNotExistBean("properNotExists"); } 復(fù)制代碼

接下來就是配置的參數(shù)

conditional.property=properExists 復(fù)制代碼

b. 實例演示

根據(jù)前面的分析,上面的四個bean中,PropertyExistBean, PropertyNotExistBean, PropertyValueExistBean 應(yīng)該存在;而PropertyValueNotExistBean 因為配置值不匹配,不會創(chuàng)建

測試代碼如下

@RestController @RequestMapping(path = "property") public class PropertyRest {@Autowired(required = false)private PropertyExistBean propertyExistBean;@Autowired(required = false)private PropertyNotExistBean propertyNotExistBean;@Autowired(required = false)private PropertyValueExistBean propertyValueExistBean;@Autowired(required = false)private PropertyValueNotExistBean propertyValueNotExistBean;@GetMapping(path = "show")public String show() {Map<String, String> result = new HashMap<>(4);// 存在result.put("propertyExistBean", propertyExistBean == null ? "null ===> false" : propertyExistBean.getName());// 存在result.put("propertyNotExistBean",propertyNotExistBean == null ? "null ===> false" : propertyNotExistBean.getName());// 存在result.put("propertyValueExistBean",propertyValueExistBean == null ? "null ==> false" : propertyValueExistBean.getName());// 不存在result.put("propertyValueNotExistBean",propertyValueNotExistBean == null ? "null ==> true" : propertyValueNotExistBean.getName());return JSONObject.toJSONString(result);} } 復(fù)制代碼

執(zhí)行后結(jié)果如下,一如預(yù)期

IV. 表達式方式

相比較前面的Bean,Class是否存在,配置參數(shù)是否存在或者有某個值而言,這個依賴SPEL表達式的,就顯得更加的高級了;其主要就是執(zhí)行Spel表達式,根據(jù)返回的true/false來判斷是否滿足條件

至于SPEL是什么東西,后面會有專文進行解釋,此處不加以展開。下面以一個簡單的demo進行演示它的使用姿勢

1. @ConditionalOnExpression

接口定義

@Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE, ElementType.METHOD }) @Documented @Conditional(OnExpressionCondition.class) public @interface ConditionalOnExpression {/*** The SpEL expression to evaluate. Expression should return {@code true} if the* condition passes or {@code false} if it fails.* @return the SpEL expression*/String value() default "true"; } 復(fù)制代碼

2. 實例測試

用一個簡單的例子,當(dāng)配置參數(shù)中,根據(jù)是否滿足某個條件來決定是否需要加載bean

a. 測試用例

定義一個滿足條件和一個不滿足的bean

public class ExpressFalseBean {private String name;public ExpressFalseBean(String name) {this.name = name;}public String getName() {return "express bean :" + name;} }public class ExpressTrueBean {private String name;public ExpressTrueBean(String name) {this.name = name;}public String getName() {return "express bean :" + name;} } 復(fù)制代碼

重點關(guān)注下bean的配置

@Configuration public class ExpressAutoConfig {/*** 當(dāng)存在配置,且配置為true時才創(chuàng)建這個bean* @return*/@Bean@ConditionalOnExpression("#{'true'.equals(environment['conditional.express'])}")public ExpressTrueBean expressTrueBean() {return new ExpressTrueBean("express true");}/*** 配置不存在,或配置的值不是true時,才創(chuàng)建bean* @return*/@Bean@ConditionalOnExpression("#{!'true'.equals(environment.getProperty('conditional.express'))}")public ExpressFalseBean expressFalseBean() {return new ExpressFalseBean("express != true");} } 復(fù)制代碼

對應(yīng)的配置如下

conditional.express=true 復(fù)制代碼

b. 實例演示

@RestController @RequestMapping(path = "express") public class ExpressRest {@Autowired(required = false)private ExpressTrueBean expressTrueBean;@Autowired(required = false)private ExpressFalseBean expressFalseBean;@GetMapping(path = "show")public String show() {Map<String, String> result = new HashMap<>(4);result.put("expressTrueBean", expressTrueBean == null ? "null ==> false" : expressTrueBean.getName());result.put("expressFalseBean", expressFalseBean == null ? "null ==> true": expressFalseBean.getName());return JSONObject.toJSONString(result);} } 復(fù)制代碼

上面的執(zhí)行,expressTrueBean應(yīng)該存在,另外一個為null,運行結(jié)果如下

III. 其他

0. 相關(guān)

a. 更多博文

基礎(chǔ)篇

  • 181009-SpringBoot基礎(chǔ)篇Bean之基本定義與使用
  • 181012-SpringBoot基礎(chǔ)篇Bean之自動加載
  • 181013-SpringBoot基礎(chǔ)篇Bean之動態(tài)注冊
  • 181018-SpringBoot基礎(chǔ)篇Bean之條件注入@Condition使用姿勢
  • 181019-SpringBoot基礎(chǔ)篇Bean之@ConditionalOnBean與@ConditionalOnClass
  • 181019-SpringBoot基礎(chǔ)篇Bean之條件注入@ConditionalOnProperty
  • 181019-SpringBoot基礎(chǔ)篇Bean之條件注入@ConditionalOnExpression

應(yīng)用篇

  • 181017-SpringBoot應(yīng)用篇Bean之注銷與動態(tài)注冊實現(xiàn)服務(wù)mock

b. 項目源碼

  • 工程:spring-boot-demo
  • module: 007-conditionbean

1. 一灰灰Blog

  • 一灰灰Blog個人博客 blog.hhui.top
  • 一灰灰Blog-Spring專題博客 spring.hhui.top

一灰灰的個人博客,記錄所有學(xué)習(xí)和工作中的博文,歡迎大家前去逛逛

2. 聲明

盡信書則不如,以上內(nèi)容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發(fā)現(xiàn)bug或者有更好的建議,歡迎批評指正,不吝感激

3. 掃描關(guān)注

一灰灰blog

總結(jié)

以上是生活随笔為你收集整理的SpringBoot基础篇Bean之条件注入之注解使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。