我正在使用spring 3.2,并希望根据条件在我的控制器中动态选择服务实现。考虑我有一个接口和两个实现如下:
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) {
}
}
因此,在我的控制器中,根据是要在本地站点还是远程站点上执行操作,我需要在本地执行它或者向远程站点发送命令来执行它。基本上,用户点击的站点确定要调用哪个服务。任何人都可以建议一个干净的方法来实现这个目标吗?
答案 0 :(得分:8)
假设您在生产环境中需要两种实现(如果不是 - 使用Spring配置文件在环境之间清楚地分割bean)。简单的方法是:
interface DevService
{
void add(Device d);
String getName();
}
@Service("devServiceLocal")
class DevServiceLocalImpl implements DevService
{
void add(Device d) {...}
String getName() {return "local";}
}
class Controller
{
@Autowired
Collection<DevService> services;
void doSomethingWithService()
{
// TODO: Check type somehow
String servType = "local";
for(DevService s: services)
{
if(servType.equals(s.getName())
{
// Call service methods
break;
}
}
}
}
答案 1 :(得分:2)
你的问题暗示,“动态”意味着你希望能够在启动时选择,但你不需要能够在中途改变它。如果是这种情况,我强烈建议使用@Profile
。我通常的做法是使用基于注释的配置,为每个配置文件都有一个单独的@Configuration
类,用于定义需要在那里提供的特定于配置文件的@Bean
。定义在生产模式下完全禁用的仅开发@Controller
甚至更容易。为每个配置文件定义一个具有String
常量的类,以避免拼写错误。
答案 2 :(得分:1)
这是未经测试的,但如果您使用的是Spring-MVC,则应该能够通过检查控制器中的标头来处理它。但是,我不确定您的代码是如何部署的。以下方法有一些缺点,但应该有效:
package <PACKAGE NAME>;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("/device")
public class DeviceController {
@RequestMapping(headers={"Host=*.local.domain.com"})
public void localDevice(
@ModelAttribute("device") Device device
) {
...
}
@RequestMapping(headers={"Host!=*.local.domain.com"})
public void remoteDevice(
@ModelAttribute("device") Device device
) {
...
}
}
即,它依赖于您的主机保持不变,而您可以为您的标头注入列表,我不确定您是否仍然可以使用该方法获取远程主机的排除映射。另外,我认为请求如何路由到控制器类中非常重要。
答案 3 :(得分:0)
您可以使用@Named
注释,并按名称获取bean。
通过这种方式,您可以定义基本名称“ServiceName”并添加一些后缀,例如“Remote”或“Local”,具体取决于您说明的条件。您还需要注释您的bean(服务实现),如
分别为 @Named("ServiceNameRemote")
和@Named("ServiceNameLocal")
最后在您的控制器上,您可以使用(DevService)BeanFactory.getBean("beanName")
通过其动态生成的名称来获取它。