I am using spring 3.2 and would like to dynamically choose a service implementation in my controller depending on a condition. Consider I have an interface and two implementations as follows :
public interface DevService {
public void add(Device device);
}
public class DevServiceImpl implements DevService {
public void add(Device device) {
}
}
public class RemoteDevServiceImpl implements DevService {
public void add(Device device) {
}
}
So in my controller, depending on whether the action is to be executed on the local site or remote site, I need to either execute it locally or send a command to the remote site to execute it. Essentially the site on which the user clicks determines which service impl to call. Can anybody suggest a clean way to achieve this ?
Your question implies that by "dynamically" you mean that you'd like to be able to select at startup time, but that you don't need to be able to change it midrun. If that's the case, I very strongly recommend using
@Profile
. My usual practice, using annotation-based configuration, is to have a separate@Configuration
class for each profile that defines the profile-specific@Bean
s that need to be available there. It's even easy to define development-only@Controller
s that are completely disabled in production mode. Define a class withString
constants for each profile to avoid typos.You can use the
@Named
annotation, and get the bean by name.In this way, you can define a base name "ServiceName" and add some suffix, like "Remote" or "Local" depending on the condition you explained. You will also need to annotate your beans (service implementations) like
@Named("ServiceNameRemote")
and@Named("ServiceNameLocal")
respectivelyFinally on your controller, you can use
(DevService)BeanFactory.getBean("beanName")
to get it by its dynamically generated name.This is untested, but if you are using Spring-MVC, you should be able to handle it by checking your headers in the controller. Though, I'm not sure how your code is being deployed. The following approach has a few downfalls, but should work:
Namely, it relies on your host staying the same, while you can inject a list for your headers, I'm not sure if you can still get the exclusion map for the remote host using that approach. Also, I think it matters greatly on how the request is routed into the controller class.
Assuming you need both implementations in production environment (if not - use Spring profiles to clearly split beans between environments). Simple approach would be: