Spring很常用的@Conditional注解的使用場(chǎng)景和源碼解析
介紹
今天要分享的是Spring的注解@Conditional,@Conditional是一個(gè)條件注解,它的作用是判斷Bean是否滿足條件,如果滿足條件,則將Bean注冊(cè)進(jìn)IOC中,如果不滿足條件,則不進(jìn)行注冊(cè),這個(gè)注解在SpringBoot中衍生出很多注解,比如@ConditionalOnProperty
,@ConditionalOnBean
,@ConditionalOnClass
等等,在SpringBoot中,這些注解用得很多。
文件服務(wù)場(chǎng)景
下面我們演示一些@Conditional的使用,在軟件開(kāi)發(fā)中,文件系統(tǒng)是必須的,但是系統(tǒng)的特點(diǎn)不一樣,有些用戶希望將文件保存在自己的服務(wù)器上,有些用戶則沒(méi)這種要求,這時(shí)候,文件可以保存在云上,也可以保存在自建文件系統(tǒng)上,那么面對(duì)不同用戶的需求,我們的軟件也要能夠適配不同的環(huán)境,只需要簡(jiǎn)單的配置即可。
假設(shè)我們?cè)陂_(kāi)發(fā)過(guò)程中,我們的文件全部托管在云服務(wù)廠商的OSS上,代碼邏輯也沒(méi)有預(yù)留擴(kuò)展,那么當(dāng)用戶需要私有化部署,我們可能就需要更改文件存儲(chǔ)這邊的邏輯,這樣的設(shè)計(jì)是不合理的。
我們想一想,文件存儲(chǔ)的代碼邏輯是不同的,各個(gè)文件系統(tǒng)的實(shí)現(xiàn)方式和使用API各不相同,但是它們有一個(gè)共性,那就是能夠上傳文件,下載文件的,所以我們就應(yīng)該抽象出一個(gè)公共接口,下面有不同的實(shí)現(xiàn),比如Minio的文件上傳下載等邏輯就使用Minio API去實(shí)現(xiàn),F(xiàn)astDFS就使用FastDFS,OSS就使用OSS,下面我們就編寫(xiě)對(duì)應(yīng)的代碼。
編碼實(shí)現(xiàn)
以下通過(guò)編碼實(shí)現(xiàn)不同文件系統(tǒng)的邏輯實(shí)現(xiàn)隔離,統(tǒng)一提供接口的方案,一般我們都會(huì)將配置信息寫(xiě)在配置文件中,在配置文件中,使用storageType代表文件存儲(chǔ)類型。
文件上傳接口
在StorageService接口中,只簡(jiǎn)單定義了兩個(gè)方法init()和put(),init()就是做一些初始化操作,比如參數(shù)配置,連接等,put()就是上傳文件接口。
/** * 功能說(shuō)明: 文件上傳接口 * <p> * Original @Author: steakliu-劉牌, 2023-04-03 09:54 * <p> */ public interface StorageService { /** * 初始化文件存儲(chǔ) */ void init(); /** * 上傳文件 * @param file */ void put(MultipartFile file); }
具體文件系統(tǒng)實(shí)現(xiàn)
以下是Minio的具體實(shí)現(xiàn),在類上面使用了@Conditional注解,value值為MinioStorageCondition
。
@Component @Conditional(value = MinioStorageCondition.class) public class MinioStorageService implements StorageService { @Override public void init() { // 初始化操作 } @Override public void put(MultipartFile file) { } }
MinioStorageCondition條件判斷
MinioStorageCondition的作用就是判斷條件是否匹配,它實(shí)現(xiàn)Condition
接口,要使用@Conditional,其判斷類必須要實(shí)現(xiàn)Condition接口,然后自己實(shí)現(xiàn)matches
方法邏輯,以下就是判斷storageType是否為minio,如果為minio,那么就返回true,就代表要?jiǎng)?chuàng)建MinioStorageService
這個(gè)bean,為false則不創(chuàng)建。
public class MinioStorageCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { String storageType = context.getEnvironment().getProperty("storageType"); return "minio".equals(storageType); } }
源碼解析
spring在掃描bean的時(shí)候,會(huì)判斷對(duì)應(yīng)的bean是否有@Conditional注解,如果有,則會(huì)進(jìn)入value中的類,進(jìn)去判斷是否符合條件,如果符合,則返回true,就能夠注冊(cè),實(shí)際上如果符合條件,那么就能將BeanDefinition注冊(cè)進(jìn)BeanFactory,如果不符合,自然不能注冊(cè)進(jìn)。
如下是源碼的時(shí)序圖
從上面的時(shí)序圖中可以看出,整個(gè)過(guò)程涉及的類還是挺多的,不過(guò)這還不是完整流程,只是從掃描類開(kāi)始,Spring會(huì)掃描工程路徑下的類,這個(gè)路徑可以通過(guò)@ComponentScan進(jìn)行指定,如果是SpringBoot項(xiàng)目,則就為當(dāng)前工程,然后篩選出需要注冊(cè)的bean并注冊(cè)到BeanFactory,對(duì)于標(biāo)注有@Conditional注解的類,會(huì)進(jìn)入@Conditional中value的類中,就是上面的MinioStorageCondition
或者FastDFSStorageCondition
,然后進(jìn)行匹配,不滿足條件的則不會(huì)被注冊(cè)。
@Conditional的具體流程也比較簡(jiǎn)單,就不一一贅述,可以看著上面的時(shí)序圖去看源碼實(shí)現(xiàn)。
總結(jié)
上面對(duì)@Conditional的使用,原理等進(jìn)行簡(jiǎn)單的介紹,@Conditional注解在SpringBoot中用得還是比較多的,特別是它衍生出來(lái)的一些注解,這些注解都是基于它來(lái)進(jìn)行二次封裝的,在SpringBoot中,對(duì)于很多starter,里面幾乎都會(huì)有@Conditional和@Conditional衍生注解的使用,我們后續(xù)會(huì)挑選出一些來(lái)說(shuō)。
以上就是Spring很常用的@Conditional注解的使用場(chǎng)景和源碼解析的詳細(xì)內(nèi)容,更多關(guān)于Spring注解@Conditional的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于break和continue以及l(fā)abel的區(qū)別和作用(詳解)
下面小編就為大家?guī)?lái)一篇關(guān)于break和continue以及l(fā)abel的區(qū)別和作用(詳解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05spring boot 下對(duì)JSON返回值去除null和空字段操作
這篇文章主要介紹了spring boot 下對(duì)JSON返回值去除null和空字段操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10MyBatis圖文并茂講解注解開(kāi)發(fā)一對(duì)多查詢
這篇文章主要介紹了SpringBoot中Mybatis注解一對(duì)多查詢的實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07Junit 5中@ParameterizedTest與@EnumSource結(jié)合使用
今天小編就為大家分享一篇關(guān)于Junit 5中@ParameterizedTest與@EnumSource結(jié)合使用,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12Java實(shí)現(xiàn)多文件壓縮加密并重命名壓縮文件對(duì)象的方法
這篇文章主要介紹了Java實(shí)現(xiàn)多文件壓縮加密并重命名壓縮文件對(duì)象的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01SpringBoot-RestTemplate實(shí)現(xiàn)調(diào)用第三方API的方式
RestTemplate?是由?Spring?提供的一個(gè)?HTTP?請(qǐng)求工具,它提供了常見(jiàn)的REST請(qǐng)求方案的模版,例如?GET?請(qǐng)求、POST?請(qǐng)求、PUT?請(qǐng)求、DELETE?請(qǐng)求以及一些通用的請(qǐng)求執(zhí)行方法?exchange?以及?execute,下面看下SpringBoot?RestTemplate調(diào)用第三方API的方式2022-12-12JAVA獲取rabbitmq消息總數(shù)過(guò)程詳解
這篇文章主要介紹了JAVA獲取rabbitmq消息總數(shù)過(guò)程詳解,公司使用的是rabbitMQ,需要做監(jiān)控預(yù)警的job去監(jiān)控rabbitMQ里面的堆積消息個(gè)數(shù),如何使用rabbitMQ獲取監(jiān)控的隊(duì)列里面的隊(duì)列消息個(gè)數(shù)呢,需要的朋友可以參考下2019-07-07Maven在Java8下如何忽略Javadoc的編譯錯(cuò)誤詳解
這篇文章主要給大家介紹了關(guān)于Maven在Java8下如何忽略Javadoc的編譯錯(cuò)誤的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08JAVA正則表達(dá)式過(guò)濾文件的實(shí)現(xiàn)方法
這篇文章主要介紹了JAVA正則表達(dá)式過(guò)濾文件的實(shí)現(xiàn)方法的相關(guān)資料,希望通過(guò)本文大家能夠掌握理解這部分內(nèi)容,需要的朋友可以參考下2017-09-09