默認狀況下,Spring中定義的bean在應用程序啓動時會所有裝配,無論當前運行的是哪一個環境(Dev,QA或者Prod),也無論當前運行的是什麼系統(Windows或者Linux),但有些使用場景下,咱們可能須要條件化的裝配某些bean,即當知足某一條件時,裝配某些bean,當不知足某一條件時,就忽略掉某些bean。java
這個條件能夠很簡單,好比當某個jar包存在時,當存在某個環境變量時,也能夠很複雜。linux
針對這個使用場景,Spring中提供了@Conditional
註解來實現條件化的bean。git
爲了更好的理解,咱們經過具體的代碼示例來理解下條件化的bean的實現方式。github
因爲Windows系統和Linux系統顯示列表的命令不一樣,Windows下是dir,Linux下是ls,所以咱們的需求是,應用程序啓動時自動根據當前系統裝配須要的bean,好比個人電腦系統是Windows 7,那就只裝配Windows系統所須要的bean。spring
首先,定義一個接口ListService,該接口只包含一個方法showListCmd:windows
package chapter03.conditional;
public interface ListService {
String showListCmd();
}
複製代碼
而後定義該接口的2個實現類WindowsListService和LinuxListService:微信
package chapter03.conditional;
public class WindowsListService implements ListService {
public WindowsListService() {
System.out.println("This is WindowsListService constructor");
}
@Override
public String showListCmd() {
return "dir";
}
}
複製代碼
package chapter03.conditional;
public class LinuxListService implements ListService {
public LinuxListService() {
System.out.println("This is LinuxListService constructor");
}
@Override
public String showListCmd() {
return "ls";
}
}
複製代碼
而後分別定義Windows系統和Linux系統的判斷條件:ide
package chapter03.conditional;
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 conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return conditionContext.getEnvironment().getProperty("os.name").contains("Windows");
}
}
複製代碼
package chapter03.conditional;
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 conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return conditionContext.getEnvironment().getProperty("os.name").contains("Linux");
}
}
複製代碼
值得注意的是,這2個類都須要實現Condition接口,並重寫方法matches(),若是該方法返回true時,使用該條件的1個或多個bean就會被裝配,若是該方法返回false,使用該條件的1個或多個bean就會被忽略。測試
而後,定義Java配置類ConditionalConfig:spa
package chapter03.conditional;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ConditionalConfig {
@Bean
@Conditional(WindowsCondition.class)
public ListService windowsListService() {
return new WindowsListService();
}
@Bean
@Conditional(LinuxCondition.class)
public ListService linuxListService() {
return new LinuxListService();
}
}
複製代碼
這裏聲明bean時除了使用@Bean註解,還使用了@Conditional註解,這個註解是實現條件化的bean的關鍵,它的參數能夠傳遞任何實現了Condition接口並重寫了matches()方法的類,這裏傳遞的是咱們上面定義的WindowsCondition和LinuxCondition。
最後,咱們定義一個Main類,在其main()方法中添加以下測試代碼:
package chapter03.conditional;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConditionalConfig.class);
ListService listService = context.getBean(ListService.class);
System.out.println(context.getEnvironment().getProperty("os.name") + "系統下的列表命令爲:" + listService.showListCmd());
context.close();
}
}
複製代碼
運行結果以下所示:
This is WindowsListService constructor
Windows 7系統下的列表命令爲:dir
從運行日誌能夠看出,因爲當前系統是Windows 7,咱們聲明的linuxListService bean並無被裝配。
源碼地址:github.com/zwwhnly/spr…,歡迎下載。
汪雲飛《Java EE開發的顛覆者:Spring Boot實戰》
Craig Walls 《Spring實戰(第4版)》
最後,歡迎關注個人微信公衆號:「申城異鄉人」,全部博客會同步更新。