當每個開發者初始化一套服務時,可能會因不同的系統或不同的Java版本相容性問題進而產生不同的Bean元件,故在此Spring 框架提供了多種條件判斷各種Bean是否要建立於IoC配置連接池中,並以設計好18種相容於既有Spring 框架的Conditional註解(Annotation)提供開發者做延用,若沒有開發者預期的Conditional註解(Annotation)類別元件,開發者可自行進行繼承實作Condition註解類別中的matches方法,進而去判斷相關的Bean是否建立於Spring IoC配置連接池中,。
@Conditional是Spring 4之後新提供的註解,主要是用來判斷是否註冊各類型的Bean類別元件接口,每個Conditional註解都會配置一個條件,當滿足此條件會將此Bean類別元件註冊於IoC配置連接池中,此註解我們可配置在類別(Class)與方法(Method)上,在於Conditional註解上分為兩種,一種是原生Spring提供,另一種為客製化動態配置類別,接下來我們將依照下方程式區段進行延伸討論。
- 原生Condition 註解判斷類型,我們將提供,我們將針對這19種Spring框架所提供的Conditional進行分析
1.1 ConditionalOnBean : IoC配置持已存在指定的Bean類別元件條件下,才可以建立此Bean類別元件。
@Bean("Pomeranian")
@ConditionalOnBean(name="Weisting")
public Dog getAnimalOfDog() {
Dog dog = new Dog();
dog.setName("Pomeranian");
dog.setType("Dog");
dog.setSound("Wong ! Wong ! Wong !");
return dog;
}
1.2 ConditionalOnClass : 目前專案存在指定的類別存在下,才可建立此Bean類別元件。
@Bean("TBaby")
@ConditionalOnClass(Animal.class)
public Turtle getAnimalOfTurtle() {
Turtle turtle = new Turtle();
turtle.setName("TBaby");
turtle.setType("Turtle");
turtle.setBehavior("Climb");
return turtle;
}
1.3 ConditionalOnMissingBean : IoC配置持不存在指定的Bean類別元件條件下,才可以建立此Bean類別元件。
@Bean("malzis")
@ConditionalOnMissingBean(name="Pomeranian")
public Dog getAnimalOfDogWithMalzis() {
Dog dog= new Dog();
dog.setName("malzis");
dog.setType("Dog");
dog.setSound("Wong ! Wong ! Wong !");
return dog;
}
1.4 ConditionalOnMissingClass : 目前專案不存在指定的類別存在下,才可建立此Bean類別元件。
@Bean("lucky")
@ConditionalOnMissingClass(value = {"sw.spring.conditional.model.Cat"})
public Dog getAnimalOfDogWithLucky() {
Dog dog= new Dog();
dog.setName("lucky");
dog.setType("Dog");
dog.setSound("Wong ! Wong ! Wong !");
return dog;
}
1.5 ConditionalOnWebApplication : 目前專案為一套WEB開發項目下,才可建立此Bean類別元件。
@Bean("husky")
@ConditionalOnWebApplication
public Dog getAnimalOfDogWithHusky() {
Dog dog= new Dog();
dog.setName("husky");
dog.setType("Dog");
dog.setSound("Wong ! Wong ! Wong !");
return dog;
}
1.6 ConditionalOnNotWebApplication : 目前專案不是為一套WEB開發項目下,才可建立此Bean類別元件。
@Bean("ghost")
@ConditionalOnNotWebApplication
public Dog getAnimalOfDogWithGhost() {
Dog dog= new Dog();
dog.setName("ghost");
dog.setType("Dog");
dog.setSound("Wong ! Wong ! Wong !");
return dog;
}
1.8 ConditionalOnProperty : 目前專案已存在指定的Properties下,才可建立此Bean類別元件。
@Bean("Bernard")
@ConditionalOnProperty(prefix = "sw.spring.conditional",name = "assert",havingValue = "true")
public Turtle getAnimalOfTurtleWithBernard() {
Turtle turtle = new Turtle();
turtle.setName("Bernard");
turtle.setType("Turtle");
turtle.setBehavior("Climb");
return turtle;
}
1.9 ConditionalOnJava : 目前專案已存在Java指定的版本下,才可建立此Bean類別元件。
@Bean("schnauzer")
@ConditionalOnJava(JavaVersion.FIFTEEN)
public Dog getAnimalOfTurtleWithSchnauzer() {
Dog dog= new Dog();
dog.setName("schnauzer");
dog.setType("Dog");
dog.setSound("Wong ! Wong ! Wong !");
return dog;
}
1.10 ConditionalOnExpression : 滿足SpEL表達式作為判斷條件下,才可建立此Bean類別元件。
@Bean("dylan")
@ConditionalOnExpression("#{'true'.equals(environment['sw.spring.conditional.assert'])}")
public Dog getAnimalOfDogWithDylan() {
Dog dog = new Dog();
dog.setName("dylan");
dog.setType("Dog");
dog.setSound("Wong ! Wong ! Wong !");
return dog;
}
1.11 ConditionalOnResource : 目前專案已存在指定的資源類別,才可建立此Bean類別元件。
@Bean("resource")
@ConditionalOnResource( resources = "classpath:/application.properties")
public Dog getAnimalOfDogWithResource() {
Dog dog = new Dog();
dog.setName("resource");
dog.setType("Dog");
dog.setSound("Wong ! Wong ! Wong !");
return dog;
}
1.12 ConditionalOnSingleCandidate : 在IoC配置池中存在指定的Bean類別元件,且為主要首選的Bean類別元件,才可建立此Bean類別元件。
@Bean("robert")
@ConditionalOnSingleCandidate(ApplicationBoot.class)
public Dog getAnimalOfDogWithSingleCandidate() {
Dog dog = new Dog();
dog.setName("robert");
dog.setType("Dog");
dog.setSound("Wong ! Wong ! Wong !");
return dog;
}
1.13 ConditionalOnRepositoryType : 當特定類別有指定的存儲庫類型(RepositoryType)存在下[其類型分為:AUTO、IMPERATIVE、NONE及REACTIVE其四種],才可建立此Bean類別元件。
@Bean("JPA-Repository")
@ConditionalOnRepositoryType(store = "JPA-Repository",type= RepositoryType.NONE)
public Turtle getAnimalOfFlyTurtle() {
Turtle turtle = new Turtle();
turtle.setName("JPA-Repository");
turtle.setType("Turtle");
turtle.setBehavior("Climb");
return turtle;
}
1.14 ConditionalOnWarDeployment : 目前專案只在war包中運作中,才可建立此Bean類別元件。
@Bean("war")
@ConditionalOnWarDeployment
public Dog getAnimalOfDogWithJNDI() {
Dog dog = new Dog();
dog.setName("war");
dog.setType("Dog");
dog.setSound("Wong ! Wong ! Wong !");
return dog;
}
1.15 ConditionalOnJndi : 若JNDI InitialContext 中的存在可用和可以查找指定位置的條件,才可建立此Bean類別元件。
1.16 ConditionalOnCloudPlatform : 若此服務建立在雲端平台服務上,目前支援僅Cloud Foundry platform、Heroku platform、SAP Cloud platform及 Kubernetes platform其四項雲端平台,才可建立此Bean類別元件。
1.17 ConditionalOnDefaultWebSecurity : 如果系統有預設Web 安全的默認配置。 且此設定會依賴Spring Framework Security套件,其套件為規範條件各類使用者運用何種身份驗證,才可建立此Bean類別元件。
1.18 ConditionalOnMissingFilterBean : 某個FilterBean元件類別的對象不存在時,才可建立此Bean類別元件。
1.19 ConditionalOnEnabledResourceChain : 會依據ResourceProperties中進行判斷三項資源是否啟用與存在,分別為spring.resources.chain.strategy.fixed.enabled、spring.resources.chain.strategy.content.enabled及spring.resources.chain.enabled,若不存在,則判斷是否存在org.webjars.WebJarAssetLocator套件,進行判斷資源是否匹配,才可建立此Bean類別元件。
2.若要客製化一個Conditional類別,必須建立一個類別並進行繼承與實作,並將此類別條件配置於該Conditional註解中,相關片段程式碼如下。
public class MacCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("os.name").contains("Mac");
}
}
---
@Bean("machine")
@Conditional(MacCondition.class)
public Dog getAnimalOfDogWithMachine() {
Dog dog = new Dog();
dog.setName("machine");
dog.setType("Dog");
dog.setSound("Wong ! Wong ! Wong !");
return dog;
}
在Conditional註解的結構中,必須預設配置一個繼承Condition介面的類別元件,此類別會實作matches的一個方法,透過此方法進行判斷是否符合條件,故無論是否為Spring框架所提供的各類Conditional註解,或開發者自身客製化的Condition條件邏輯方法,都會經由主要的核心註解(Conditional)進行請求判斷(invoke)。
圖一 Conditional 架構圖
Run test task
gradle test
Run open result html
open ./build/reports/tests/test/index.html
Test Class Sample
Test Details.