Spring 條件註解

一、簡介

在本教程中,我們將看看@Conditional註釋。它用於根據定義的條件指示給定組件是否有資格註冊。

我們將學習如何使用預定義的條件註釋,將它們與不同的條件結合起來,以及創建我們自定義的、基於條件的註釋。

2.使用Conditional註釋

在我們進入實現之前,讓我們首先看看我們可以在哪些情況下使用條件註釋。

最常見的用法是包含或排除整個配置類

@Configuration

 @Conditional(IsDevEnvCondition.class)

 class DevEnvLoggingConfiguration {

 // ...

 }

或者只是一個 bean:

@Configuration

 class DevEnvLoggingConfiguration {



 @Bean

 @Conditional(IsDevEnvCondition.class)

 LoggingService loggingService() {

 return new LoggingService();

 }

 }

通過這樣做,我們可以將應用程序的行為基於給定的條件。例如,我們客戶的環境類型或特定需求。在上面的例子中,我們只為開發環境初始化了額外的日誌服務。

使組件有條件的另一種方法是將條件直接放在組件類上:

@Service

 @Conditional(IsDevEnvCondition.class)

 class LoggingService {

 // ...

 }

我們可以將上面的例子應用於任何用@Component@Service@Repository,@Controller註釋聲明的 bean。

3. 預定義的條件註釋

Spring 帶有一組預定義的條件註釋。讓我們來看看一些最受歡迎的。

首先,讓我們看看如何基於配置屬性值構建組件:

@Service

 @ConditionalOnProperty(

 value="logging.enabled",

 havingValue = "true",

 matchIfMissing = true)

 class LoggingService {

 // ...

 }

第一個屬性value,告訴我們要查看的配置屬性。第二個, havingValue,定義了這個條件所需的值。最後, matchIfMissing屬性告訴 Spring 如果缺少參數,是否應該匹配條件。

同樣,我們可以將條件基於表達式

@Service

 @ConditionalOnExpression(

 "${logging.enabled:true} and '${logging.level}'.equals('DEBUG')"

 )

 class LoggingService {

 // ...

 }

現在,只有在logging.enabled配置屬性設置為true,並且logging.level設置為DEBUG.時,Spring 才會創建LoggingService

我們可以應用的另一個條件是檢查是否創建了給定的 bean:

@Service

 @ConditionalOnBean(CustomLoggingConfiguration.class)

 class LoggingService {

 // ...

 }

或者類路徑上存在給定的類:

@Service

 @ConditionalOnClass(CustomLogger.class)

 class LoggingService {

 // ...

 }

@ConditionalOnMissingBean@ConditionalOnMissingClass註釋來實現相反的行為。

此外,我們可以將組件依賴於給定的 Java 版本

@Service

 @ConditionalOnJava(JavaVersion.EIGHT)

 class LoggingService {

 // ...

 }

在上面的例子中, LoggingService只會在運行時環境為 Java 8 時被創建。

最後,我們可以使用@ConditionalOnWarDeployment註解來只在war包中啟用bean:

@Configuration

 @ConditionalOnWarDeployment

 class AdditionalWebConfiguration {

 // ...

 }

請注意,對於帶有嵌入式服務器的應用程序,此條件將返回 false。

4.定義自定義條件

Spring 允許我們通過創建自定義條件模板來自定義@Conditional註釋的行為。要創建一個,我們只需要實現Condition接口:

class Java8Condition implements Condition {

 @Override

 public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

 return JavaVersion.getJavaVersion().equals(JavaVersion.EIGHT);

 }

 }

matches方法告訴Spring條件是否已通過。它有兩個參數,分別為我們提供有關 bean 將初始化的上下文和使用的@Conditional註釋的元數據的信息。

如我們所見,在我們的示例中,我們只檢查 Java 版本是否為 8。

之後,我們應該將我們的新條件作為@Conditional註釋中的一個屬性:

@Service

 @Conditional(Java8Condition.class)

 public class Java8DependedService {

 // ...

 }

這樣, Java8DependentService將僅在從條件創建Java8Condition類匹配。

5.合併條件

對於更複雜的解決方案,我們可以使用 OR 或 AND 邏輯運算符對條件註釋進行分組

要應用 OR 運算符,我們需要創建一個擴展AnyNestedCondition類的自定義條件。在其中,我們需要static類,並使用適當的@Conditional實現對其進行註釋。

例如,讓我們創建一個需要 Java 8 或 Java 9 的條件:

class Java8OrJava9 extends AnyNestedCondition {



 Java8OrJava9() {

 super(ConfigurationPhase.REGISTER_BEAN);

 }



 @Conditional(Java8Condition.class)

 static class Java8 { }



 @Conditional(Java9Condition.class)

 static class Java9 { }



 }

另一方面,AND 運算符要簡單得多。我們可以簡單地將條件分組:

@Service

 @Conditional({IsWindowsCondition.class, Java8Condition.class})

 @ConditionalOnJava(JavaVersion.EIGHT)

 public class LoggingService {

 // ...

 }

在上面的例子中, IsWindowsConditionJava8Condition都匹配時才會創建LoggingService