Spring 條件註解
- 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 {
// ...
}
在上面的例子中, IsWindowsCondition
和Java8Condition
都匹配時才會創建LoggingService