You can obtain your bean from the context by name dynamically using a BeanFactory:
@Service
public class Doer {
@Autowired BeanFactory beans;
public void doSomething(Case case){
CaseService service = beans.getBean(case.getCountryCode(), CaseService.class)
service.doSomething(case);
}
}
A side note. Using something like country code as bean name looks a bit odd. Add at least some prefix or better consider some other design pattern.
If you still like to have bean per country, I would suggest another approach. Introduce a registry service to get a required service by country code:
@Service
public class CaseServices {
private final Map<String, CaseService> servicesByCountryCode = new HashMap<>();
@Autowired
public CaseServices(List<CaseService> services){
for (CaseService service: services){
register(service.getCountryCode(), service);
}
}
public void register(String countryCode, CaseService service) {
this.servicesByCountryCode.put(countryCode, service);
}
public CaseService getCaseService(String countryCode){
return this.servicesByCountryCode.get(countryCode);
}
}
Example usage:
@Service
public class DoService {
@Autowired CaseServices caseServices;
public void doSomethingWith(Case case){
CaseService service = caseServices.getCaseService(case.getCountryCode());
service.modify(case);
}
}
In this case you have to add String getCountryCode()
method to your CaseService
interface.
public interface CaseService {
void modify(Case case);
String getCountryCode();
}
Alternatively, you can add method CaseService.supports(Case case)
to select the service. Or, if you cannot extend the interface, you can call CaseServices.register(String, CaseService)
method from some initialiser or a @Configuration
class.
UPDATE: Forgot to mention, that Spring already provides a nice Plugin abstraction to reuse boilerplate code for creating PluginRegistry
like this.
Example:
public interface CaseService extends Plugin<String>{
void doSomething(Case case);
}
@Service
@Priority(0)
public class SwissCaseService implements CaseService {
void doSomething(Case case){
// Do something with the Swiss case
}
boolean supports(String countryCode){
return countryCode.equals("CH");
}
}
@Service
@Priority(Ordered.LOWEST_PRECEDENCE)
public class DefaultCaseService implements CaseService {
void doSomething(Case case){
// Do something with the case by-default
}
boolean supports(String countryCode){
return true;
}
}
@Service
public class CaseServices {
private final PluginRegistry<CaseService<?>, String> registry;
@Autowired
public Cases(List<CaseService> services){
this.registry = OrderAwarePluginRegistry.create(services);
}
public CaseService getCaseService(String countryCode){
return registry.getPluginFor(countryCode);
}
}