Mastering Spring’s @Autowired for Collections: From Lists to Maps
This article explains how Spring’s @Autowired can inject List, Set, and Map collections, detailing injection mechanisms, code examples, workflow steps, common use cases like plugin systems and filter chains, and advanced tips such as @Qualifier, custom ordering, and handling pitfalls.
Spring @Autowired on Collections
Spring’s @Autowired annotation can be applied to collection types such as List , Set , and Map . When used on a collection, Spring automatically discovers all beans of the element type and injects them into the collection.
This mechanism is ideal for plugin architectures, filter chains, multi‑strategy implementations, and other scenarios that require loose coupling and automatic aggregation of multiple implementations.
Common collection injection forms: List<BeanType> – injects all matching beans, preserving order and allowing duplicates. Set<BeanType> – injects all matching beans without duplicates. Map<String, BeanType> – injects beans with their bean name as the key. Map<Class<?>, BeanType> – injects beans with their type as the key.
Detailed Parsing
1. List Injection
When a @Autowired List is injected, Spring collects all matching beans and orders them according to @Order or the Ordered interface.
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;
// 过滤器接口
public interface 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
public class FilterChainService {
private final 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;
}
}2. Set Injection
Set injection works like List but eliminates duplicate beans.
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;
// 验证器接口
public interface 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
public class ValidationService {
private final 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> Injection
Map injection uses the bean name as the 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;
// 处理器接口
public interface 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
public class ProcessorService {
private final 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 {
throw new IllegalArgumentException("不支持的数据类型:" + type);
}
}
}How Collection Injection Works
Identify collection type : Spring detects that the injection point is a List, Set, or Map.
Determine element type : Generic information is used to find the element class.
Collect matching beans : All beans of that type are retrieved from the container.
Order if needed : For Lists, beans are sorted by @Order or Ordered.
Inject collection : The assembled collection is injected into the target.
An illustrative flow diagram:
Typical Use Cases
Plugin systems – automatic discovery and registration.
Filter/Interceptor chains – ordered processing pipelines.
Multiple strategy implementations – select implementation based on conditions.
Command handlers – route commands to appropriate processors.
Validator collections – combine several validation rules.
Event listeners – auto‑register listeners.
Advanced Features & Caveats
1. Precise control with @Qualifier
When multiple beans of the same type exist, @Qualifier can limit which beans are injected.
@Autowired
@Qualifier("highPriority")
private List<TaskProcessor> highPriorityProcessors;2. Custom ordering
Beyond @Order, implementing Ordered or PriorityOrdered gives fine‑grained control.
@Component
public class CriticalFilter implements RequestFilter, PriorityOrdered {
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE; // highest priority
}
@Override
public String filter(String request) {
// implementation
}
}3. Generic type qualifiers
Spring can narrow injection by generic type, e.g., injecting only Repository<User> beans.
interface Repository<T> { /* ... */ }
@Component
class UserRepository implements Repository<User> { /* ... */ }
@Component
class ProductRepository implements Repository<Product> { /* ... */ }
@Service
class Service {
@Autowired
private List<Repository<User>> userRepositories; // only UserRepository injected
}4. Important considerations
Circular dependencies : Collection injection may introduce circular references.
Performance impact : Large numbers of beans can increase startup time.
Order stability : Unordered collections have nondeterministic ordering.
Empty collections : If no matching beans are found, Spring injects an empty collection rather than null.
Xuanwu Backend Tech Stack
Primarily covers fundamental Java concepts, mainstream frameworks, deep dives into underlying principles, and JVM internals.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
