1. 簡介
在本簡短教程中,我們將演示如何在 Spring 中動態地自動注入一個 Bean。
我們將首先介紹一個實際應用場景,其中動態自動注入可能很有用。此外,我們還將展示兩種不同的方法來解決該問題。
2. 動態自動裝配的應用場景
動態自動裝配在需要動態改變 Spring 容器的 Bean 執行邏輯的地方非常有用。它尤其適用於在運行時變量決定要執行的代碼時。
為了演示一個實際應用場景,我們創建一個控制全球不同地區的服務器的應用。為此,我們創建了一個接口,其中包含兩個簡單的方法:
public interface RegionService {
boolean isServerActive(int serverId);
String getISOCountryCode();
}並且兩個實現:
@Service("GBregionService")
public class GBRegionService implements RegionService {
@Override
public boolean isServerActive(int serverId) {
return false;
}
@Override
public String getISOCountryCode() {
return "GB";
}
}@Service("USregionService")
public class USRegionService implements RegionService {
@Override
public boolean isServerActive(int serverId) {
return true;
}
@Override
public String getISOCountryCode() {
return "US";
}
}讓我們假設我們有一個網站,用户可以選擇檢查所選區域的服務器是否處於活動狀態。因此,我們希望有一個服務類,該類根據用户的輸入動態地更改 RegionService 接口的實現。這正是動態 Bean 自動裝入發揮作用的用例。
3. 使用 BeanFactory
BeanFactory 是訪問 Spring Bean 容器的根接口。它尤其包含用於獲取特定 Bean 的有用方法。由於 BeanFactory 也是一個 Spring Bean,因此我們可以直接在我們的類中使用它並進行自動注入:
@Service
public class BeanFactoryDynamicAutowireService {
private static final String SERVICE_NAME_SUFFIX = "regionService";
private final BeanFactory beanFactory;
@Autowired
public BeanFactoryDynamicAutowireService(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public boolean isServerActive(String isoCountryCode, int serverId) {
RegionService service = beanFactory.getBean(getRegionServiceBeanName(isoCountryCode),
RegionService.class);
return service.isServerActive(serverId);
}
private String getRegionServiceBeanName(String isoCountryCode) {
return isoCountryCode + SERVICE_NAME_SUFFIX;
}
}我們使用了重載的 getBean() 方法來獲取指定名稱和類型的 Bean。
雖然這種方法可行,但我們更傾向於使用更地道的方案,即依賴注入。
4. 使用接口
為了解決這個問題,我們將依賴 Spring 中一個不太為人熟知的特性。
除了標準的單字段自動注入功能,Spring 賦予我們一種將所有實現特定接口的 Bean 收集到Map 的能力:
@Service
public class CustomMapFromListDynamicAutowireService {
private final Map<String, RegionService> servicesByCountryCode;
@Autowired
public CustomMapFromListDynamicAutowireService(List<RegionService> regionServices) {
servicesByCountryCode = regionServices.stream()
.collect(Collectors.toMap(RegionService::getISOCountryCode, Function.identity()));
}
public boolean isServerActive(String isoCountryCode, int serverId) {
RegionService service = servicesByCountryCode.get(isoCountryCode);
return service.isServerActive(serverId);
}
}我們創建了一個地圖,該地圖通過國家代碼存儲了實現方案。 稍後,我們可以在方法中使用它來獲取特定實現方案,以檢查給定服務器是否在特定區域處於活動狀態。
5. 結論
在本快速教程中,我們學習瞭如何使用兩種不同的方法在 Spring 中動態地自動注入一個 Bean。