Spring的@Autowired能用在集合上嗎?
面試回答
Spring的@Autowired
注解可以用在各種 集合類型 上,包括List、Set、Map等。這是Spring框架提供的一種強大特性,允許我們 自動收集和注入同一類型的多個bean 。當@Autowired
用于集合時,Spring會自動查找所有符合類型的bean,并將它們注入到集合中。
這種機制非常適合實現插件架構、處理器鏈、多策略實現等場景,使我們能夠以松耦合方式擴展應用功能。比如,我們可以定義一個接口,然后提供多個實現,讓Spring自動收集這些實現并注入到集合中,無需手動注冊每個實現。
Spring支持以下幾種常見的集合注入方式:
List<BeanType>
- 注入所有符合類型的bean,可以包含重復的beanSet<BeanType>
- 注入所有符合類型的bean,不包含重復項Map<String, BeanType>
- 以bean名稱為key,bean實例為value進行注入Map<Class<?>, BeanType>
- 以bean類型為key,bean實例為value進行注入
詳細解析
1. List注入
使用@Autowired
注入List時,Spring會自動收集所有符合類型的bean,并按照@Order
注解或Ordered
接口指定的順序注入到List中。
package com.qy.filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import java.util.List;
// 過濾器接口
publicinterface RequestFilter {
String filter(String request);
}
// 安全過濾器
@Component
@Order(1) // 指定順序為1,最先執行
class SecurityFilter implements RequestFilter {
@Override
public String filter(String request) {
System.out.println("執行安全過濾");
return request + " [已安全過濾]";
}
}
// 日志過濾器
@Component
@Order(2) // 指定順序為2,第二執行
class LoggingFilter implements RequestFilter {
@Override
public String filter(String request) {
System.out.println("執行日志記錄");
return request + " [已記錄日志]";
}
}
// 緩存過濾器
@Component
@Order(3) // 指定順序為3,最后執行
class CachingFilter implements RequestFilter {
@Override
public String filter(String request) {
System.out.println("執行緩存處理");
return request + " [已緩存]";
}
}
// 過濾器鏈服務
@Service
publicclass FilterChainService {
privatefinal List<RequestFilter> filters;
@Autowired
public FilterChainService(List<RequestFilter> filters) {
this.filters = filters;
System.out.println("已注入過濾器數量:" + filters.size());
}
public String processRequest(String request) {
String result = request;
for (RequestFilter filter : filters) {
result = filter.filter(result);
}
return result;
}
}
在這個例子中,Spring會將所有RequestFilter
的實現按照@Order
注解指定的順序注入到List中,使得過濾器可以按照預定順序執行。
2. Set注入
Set注入與List類似,但會確保沒有重復的bean:
package com.qy.validator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import java.util.Set;
// 驗證器接口
publicinterface Validator {
boolean validate(String data);
String getValidatorName();
}
// 非空驗證器
@Component
class NotEmptyValidator implements Validator {
@Override
public boolean validate(String data) {
boolean valid = data != null && !data.trim().isEmpty();
System.out.println("非空驗證: " + (valid ? "通過" : "失敗"));
return valid;
}
@Override
public String getValidatorName() {
return"非空驗證器";
}
}
// 長度驗證器
@Component
class LengthValidator implements Validator {
@Override
public boolean validate(String data) {
boolean valid = data != null && data.length() <= 100;
System.out.println("長度驗證: " + (valid ? "通過" : "失敗"));
return valid;
}
@Override
public String getValidatorName() {
return"長度驗證器";
}
}
// 驗證服務
@Service
publicclass ValidationService {
privatefinal Set<Validator> validators;
@Autowired
public ValidationService(Set<Validator> validators) {
this.validators = validators;
System.out.println("已注入驗證器:");
validators.forEach(v -> System.out.println("- " + v.getValidatorName()));
}
public boolean validate(String data) {
return validators.stream().allMatch(v -> v.validate(data));
}
}
3. Map<String, BeanType>注入
使用Map注入時,可以將bean的名稱作為key:
package com.qy.processor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import java.util.Map;
// 處理器接口
publicinterface DataProcessor {
String process(String data);
}
// JSON處理器
@Component("json")
class JsonProcessor implements DataProcessor {
@Override
public String process(String data) {
System.out.println("處理JSON數據");
return"{\"processed\": \"" + data + "\"}";
}
}
// XML處理器
@Component("xml")
class XmlProcessor implements DataProcessor {
@Override
public String process(String data) {
System.out.println("處理XML數據");
return"<processed>" + data + "</processed>";
}
}
// 處理服務
@Service
publicclass ProcessorService {
privatefinal Map<String, DataProcessor> processorMap;
@Autowired
public ProcessorService(Map<String, DataProcessor> processorMap) {
this.processorMap = processorMap;
System.out.println("已注入數據處理器:" + processorMap.keySet());
}
public String processData(String type, String data) {
DataProcessor processor = processorMap.get(type);
if (processor != null) {
return processor.process(data);
} else {
thrownew IllegalArgumentException("不支持的數據類型:" + type);
}
}
}
集合注入的工作原理
當Spring遇到集合類型的@Autowired
注入點時,會按照以下步驟處理:
- 識別集合類型:Spring識別字段或參數是集合類型(List、Set、Map等)
- 提取元素類型:通過泛型信息獲取集合元素的類型
- 收集匹配的bean:查找容器中所有與元素類型匹配的bean
- 排序(如果需要):對于List,根據@Order或Ordered接口排序
- 注入集合:將收集到的bean注入到集合中
下面是Spring處理集合注入的簡化流程圖
圖片
集合注入的應用場景
- 插件系統:自動發現和注冊插件,無需手動配置
- 過濾器鏈/攔截器鏈:構建有序的處理管道
- 多策略實現:根據不同條件選擇不同的處理策略
- 命令處理器:根據命令類型自動路由到對應處理器
- 驗證器集合:組合多個驗證規則
- 事件監聽器:自動收集并注冊事件監聽器
高級特性和注意事項
1. 使用@Qualifier精確控制注入
當有多個同類型的bean時,可以使用@Qualifier
注解來指定具體要注入哪些bean:
@Autowired
@Qualifier("highPriority")
private List<TaskProcessor> highPriorityProcessors;
2. 自定義排序
除了@Order
注解外,還可以實現Ordered
接口或PriorityOrdered
接口來控制bean的順序:
@Component
public class CriticalFilter implements RequestFilter, PriorityOrdered {
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE; // 最高優先級
}
@Override
public String filter(String request) {
// 實現代碼
}
}
3. 使用泛型類型作為限定符
Spring支持使用泛型作為自動裝配的限定條件:
interface Repository<T> { /* ... */ }
@Component
class UserRepository implements Repository<User> { /* ... */ }
@Component
class ProductRepository implements Repository<Product> { /* ... */ }
@Service
class Service {
@Autowired
private List<Repository<User>> userRepositories; // 只注入UserRepository
}
4. 注意事項
- 循環依賴:集合注入可能導致循環依賴問題,需要謹慎處理
- 性能影響:大量的集合注入可能影響應用啟動性能
- 順序穩定性:未指定順序的集合注入不保證順序穩定性
- 空集合處理:當沒有匹配的bean時,Spring會注入空集合而不是null