知識庫 / Spring / Spring Boot RSS 訂閱

Spring 條件註解

Spring Boot
HongKong
4
12:31 PM · Dec 06 ,2025

1. 簡介

本教程將介紹 @Conditional 註解。它用於指示某個組件是否根據定義的條件具有註冊資格。

我們將學習如何使用預定義的條件註解,以及如何將它們與不同的條件組合,並創建自定義的基於條件的註解。

2. 聲明條件

在深入實施之前,讓我們看看我們如何利用條件註解在哪些情況下發揮作用。

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

@Configuration
@Conditional(IsDevEnvCondition.class)
class DevEnvLoggingConfiguration {
    // ...
}

或者僅僅是一個豆子:

@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 提供了若干預定義的條件註解。下面我們來了解一些最常用的註解。

首先,我們來看如何根據配置屬性值來基於組件:

@ConfigurationProperties // 示例代碼註釋
@Service
@ConditionalOnProperty(
  value="logging.enabled", 
  havingValue = "true", 
  matchIfMissing = true)
class LoggingService {
    // ...
}

第一個屬性, 告訴我們我們將要查看的配置屬性。第二個屬性, 定義了用於此條件的所需值。最後, 屬性告訴 Spring 如果參數缺失,條件是否應匹配。

同樣,我們可以基於一個表達式來定義條件:

@Service
@ConditionalOnExpression(
  "${logging.enabled:true} and '${logging.level}'.equals('DEBUG')"
)
class LoggingService {
    // ...
}

現在 Spring 只會在 LoggingService 被創建,前提是 logging.enabled 配置屬性設置為 true, 並且 logging.level 設置為 DEBUG.

另一個可以應用的條件是檢查給定類是否在類路徑上存在:

@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。

此外,Spring Boot 提供了 @ConditionalOnBean 註解。與我們之前見過的其他 @ConditionalOn* 註解不同,@ConditionalOnBean 只能與通過應用程序上下文已處理的 Bean 定義相匹配。因此,我們應該僅將其用於自動配置類。關於 Spring Boot 自動配置,我們有一篇專門的文章來解釋如何創建自定義自動配置。

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 運算符,我們需要創建一個自定義條件,該條件擴展了 <a href="https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/condition/AnyNestedCondition.html" target="_blank">AnyNestedCondition</a> 類。 在其中,我們需要為每個條件創建一個空靜態類,並使用適當的@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 {
    // ...
}

在上述示例中,LoggingService 只會在 IsWindowsConditionJava8Condition 匹配時才創建。

6. 總結

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.