Injecting Collections with @Autowired and Applying Strategy Pattern in Spring
This article demonstrates how Spring's @Autowired annotation can inject arrays, lists, sets, and maps of beans, shows code examples for retrieving all PayService implementations, and explains how to combine this feature with the strategy pattern to route payment channels dynamically.
Spring developers are familiar with the @Autowired annotation for automatic bean injection, but it can also inject collections such as arrays, List, Set, and even Map of a specific type.
Consider a payment system with a PayService interface and three implementations: AliPayService, WechatPayService, and BankCardPayService. To obtain all PayService beans, you can use the traditional approaches:
String[] names = ctx.getBeanNamesForType(PayService.class);
List<PayService> anotherPayService = Lists.newArrayList();
for (String beanName : names) {
anotherPayService.add(ctx.getBean(beanName, PayService.class));
}
// or
Map<String, PayService> beansOfType = ctx.getBeansOfType(PayService.class);
for (Map.Entry<String, PayService> entry : beansOfType.entrySet()) {
anotherPayService.add(entry.getValue());
}With collection injection, the same goal is achieved more concisely:
@Autowired
List<PayService> payServices;
@Autowired
PayService[] payServicesArray;Using this capability, the strategy pattern becomes straightforward. Define a common PayService interface, implement it for each payment channel, and inject all implementations as a collection. A RouteService can then map a request's channelNo to the appropriate bean.
@Service
public class RouteService {
@Autowired
Map<String, PayService> payServiceMap;
public PayResult epay(PayRequest payRequest) {
PayService payService = payServiceMap.get(payRequest.getChannelNo());
return payService.epay(payRequest);
}
}To avoid relying on bean names that match numeric channel codes, extend the PayService interface with a String channel() method, let each implementation return its unique identifier, and build the map programmatically after injection:
@Service
public class RouteService {
@Autowired
Set<PayService> payServiceSet;
Map<String, PayService> payServiceMap;
@PostConstruct
public void init() {
payServiceMap = new HashMap<>();
for (PayService payService : payServiceSet) {
payServiceMap.put(payService.channel(), payService);
}
}
public PayResult epay(PayRequest payRequest) {
PayService payService = payServiceMap.get(payRequest.getChannelNo());
return payService.epay(payRequest);
}
}This approach cleanly separates payment channel differences, making the system easier to maintain and extend.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
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.
