
文章目錄
1. 前言
我們經常會有根據條件來加載不同的接口。比如你查詢目錄下文件列表, Windows 下你會用 CMD 的 dir 命令,而 Linux 下你會使用 ls 命令。 熟悉 Spring Boot 自動配置的也知道 Spring Boot 能根據不同的實際情況啟用不同的配置。這就是@Conditional注解在發揮作用。
該注解指定了在什么條件下創建 Bean 進行配置。
2. @Conditional 注解
Spring Boot 包含多個 @Conditional 注釋,可以在@Configuration注解的類和@Bean注解方法中使用。@Conditional類型的注解,可以注解在類上,可以注解在Bean方法上,可以允許基於Spring Environment屬性包含配置,可以僅允許在存在特定資源時包含配置。也可自定義,接下來我們來熟悉一下 Spring Boot 提供的一些具體的條件注解。
2.1 Class Conditions
@ConditionalOnClass和@ConditionalOnMissingClass 兩個在類上的注解:
判斷指定的類是否存在來構建自動配置,也可使用name屬性名來指定類名。
2.2 Bean Conditions
@ConditionalOnBean和@ConditionalOnMissingBean 兩個在 Bean 方法上的注解:
判斷指定的 Bean 是否存在來構建自動配置,可以使用value屬性來按類型或名稱(id)指定 Bean, 可以使用search屬性指定 ApplicationContext 層次結構來搜索Bean。
@Configuration
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService() { ... }
}
要添加注意添加 Bean 時的順序,官方建議在自動配置類上僅使用 @ConditionalOnBean和@ConditionalOnMissingBean注釋,因為可以保證這些注釋在添加用戶定義的Bean后執行。
@ConditionalOnBean和@ConditionalOnMissingBean注解作用在@Configuration注釋的類上,等同於在作用在每個包含@Bean的方法上。
2.3 Property Conditions
@ConditionalOnProperty注解可以基於Spring Environment屬性包含的配置進判斷,再決定自動配置的執行,使用 prefix 和 name 屬性指定應檢查的屬性。默認情況下,匹配存在且不等於false的任何屬性。 您還可以使用havingValue和matchIfMissing屬性創建更高級的檢查。
2.4 Resource Conditions
@ConditionalOnResource注釋僅允許在存在特定資源時執行自動配置。 可以使用常用的 Spring 約定來指定資源,如以下示例所示:file:/home/user/test.dat。
2.5 Web Application Conditions
@ConditionalOnWebApplication和@ConditionalOnNotWebApplication注解用於判斷應用程序是否為Web應用程序,Web應用程序是使用Spring WebApplicationContext,定義會話范圍或具有StandardServletEnvironment的任何應用程序。
2.6 SpEL Expression Conditions
@ConditionalOnExpression注解允許根據SpEL表達式的結果來執行配置。
3. 自定義 Condition
如果上面幾種都不能滿足你的需要。那么我們可以通過實現Condition接口,並重寫其matches方法來構造判斷條件。
- 1.實現 Condition 接口來定義判斷條件
//Windows系統的判斷條件
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("os.name").contains("Windows");
}
}
//Linux系統的判斷條件
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("os.name").contains("Linux");
}
}
- 2.實現不同系統下的Bean類
//接口
public interface ListService {
public String showListCmd();
}
//Windows下的實現類
public class WindowsListServiceImpl implements ListService {
@Override
public String showListCmd() {
return "dir";
}
}
//Linux下的實現類
public class LinuxListServiceImpl implements ListService {
@Override
public String showListCmd() {
return "ls";
}
}
- 3.配置類
@Conditional注解調用條件判斷的類並根據返回的結果來創建Bean
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ConditionConfig {
@Bean
@Conditional(WindowsCondition.class)
public ListService windowsListService() {
return new WindowsListServiceImpl();
}
@Bean
@Conditional(LinuxCondition.class)
public ListService linuxListService() {
return new LinuxListServiceImpl();
}
}
- 4.運行類
@RunWith(SpringRunner.class)
@SpringBootTest
public class SecurityLearningApplicationTests {
@Resource
private ListService listService ;
@Resource
private ApplicationContext context;
public void testCondition(){
System.out.println(context.getEnvironment().getProperty("os.name")
"系統下的列表命令:"
listService.showListCmd());
}
}
4. 總結
今天我們對 Spring Boot 中的 Condition 條件判斷注入進行了系統性的了解。不僅對 Spring Boot 提供的一些開箱即用的 Condition 進行了學習,還實現了自定義的 Condition 。如果你要對 Spring Boot 的自動配置深入學習或者根據業務來靈活定制,就必須對 Condition 進行系統性的學習。
關注公眾號:Felordcn獲取更多資訊
