你好,我是劉牌!
今天要分享的是Spring的註解@Conditional,@Conditional是一個條件註解,它的作用是判斷Bean是否滿足條件,如果滿足條件,則將Bean註冊進IOC中,如果不滿足條件,則不進行註冊,這個註解在SpringBoot中衍生出很多註解,比如@ConditionalOnProperty
,@ConditionalOnBean
,@ConditionalOnClass
等等,在SpringBoot中,這些註解用得很多。
下面我們演示一些@Conditional的使用,在軟體開發中,檔案系統是必須的,但是系統的特點不一樣,有些使用者希望將檔案儲存在自己的伺服器上,有些使用者則沒這種要求,這時候,檔案可以儲存在雲上,也可以儲存在自建檔案系統上,那麼面對不同使用者的需求,我們的軟體也要能夠適配不同的環境,只需要簡單的設定即可。
假設我們在開發過程中,我們的檔案全部託管在雲服務廠商的OSS上,程式碼邏輯也沒有預留擴充套件,那麼當用戶需要私有化部署,我們可能就需要更改檔案儲存這邊的邏輯,這樣的設計是不合理的。
我們想一想,檔案儲存的程式碼邏輯是不同的,各個檔案系統的實現方式和使用API各不相同,但是它們有一個共性,那就是能夠上傳檔案,下載檔案的,所以我們就應該抽象出一個公共介面,下面有不同的實現,比如Minio的檔案上傳下載等邏輯就使用Minio API去實現,FastDFS就使用FastDFS,OSS就使用OSS,下面我們就編寫對應的程式碼。
以下通過編碼實現不同檔案系統的邏輯實現隔離,統一提供介面的方案,一般我們都會將設定資訊寫在組態檔中,在組態檔中,使用storageType代表檔案儲存型別。
在StorageService介面中,只簡單定義了兩個方法init()和put(),init()就是做一些初始化操作,比如引數設定,連線等,put()就是上傳檔案介面。
/**
* 功能說明: 檔案上傳介面
* <p>
* Original @Author: steakliu-劉牌, 2023-04-03 09:54
* <p>
*/
public interface StorageService {
/**
* 初始化檔案儲存
*/
void init();
/**
* 上傳檔案
* @param file
*/
void put(MultipartFile file);
}
以下是Minio的具體實現,在類上面使用了@Conditional註解,value值為MinioStorageCondition
。
@Component
@Conditional(value = MinioStorageCondition.class)
public class MinioStorageService implements StorageService {
@Override
public void init() {
// 初始化操作
}
@Override
public void put(MultipartFile file) {
}
}
MinioStorageCondition的作用就是判斷條件是否匹配,它實現Condition
介面,要使用@Conditional,其判斷類必須要實現Condition介面,然後自己實現matches
方法邏輯,以下就是判斷storageType是否為minio,如果為minio,那麼就返回true,就代表要建立MinioStorageService
這個bean,為false則不建立。
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的時候,會判斷對應的bean是否有@Conditional註解,如果有,則會進入value中的類,進去判斷是否符合條件,如果符合,則返回true,就能夠註冊,實際上如果符合條件,那麼就能將BeanDefinition註冊進BeanFactory,如果不符合,自然不能註冊進。
如下是原始碼的時序圖
從上面的時序圖中可以看出,整個過程涉及的類還是挺多的,不過這還不是完整流程,只是從掃描類開始,Spring會掃描工程路徑下的類,這個路徑可以通過@ComponentScan進行指定,如果是SpringBoot專案,則就為當前工程,然後篩選出需要註冊的bean並註冊到BeanFactory,對於標註有@Conditional註解的類,會進入@Conditional中value的類中,就是上面的MinioStorageCondition
或者FastDFSStorageCondition
,然後進行匹配,不滿足條件的則不會被註冊。
@Conditional的具體流程也比較簡單,就不一一贅述,可以看著上面的時序圖去看原始碼實現。
上面對@Conditional的使用,原理等進行簡單的介紹,@Conditional註解在SpringBoot中用得還是比較多的,特別是它衍生出來的一些註解,這些註解都是基於它來進行二次封裝的,在SpringBoot中,對於很多starter,裡面幾乎都會有@Conditional和@Conditional衍生註解的使用,我們後續會挑選出一些來說。
今天的分享就到這裡,感謝你的觀看,我們下期見!