Spring Boot 2 實戰:根據條件來自動配置不同邏輯的Bean



1. 前言

我們經常會有根據條件來加載不同的接口。比如你查詢目錄下文件列表, Windows 下你會用 CMDdir 命令,而 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屬性包含的配置進判斷,再決定自動配置的執行,使用 prefixname 屬性指定應檢查的屬性。默認情況下,匹配存在且不等於false的任何屬性。 您還可以使用havingValuematchIfMissing屬性創建更高級的檢查。

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獲取更多資訊

個人博客:https://felord.cn


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM