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.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Injecting Collections with @Autowired and Applying Strategy Pattern in Spring

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Strategy PatternAutowireddependency-injection
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.