文章目錄
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獲取更多資訊