Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在Spring中使用接口的动态实现?_Java_Spring_Spring Mvc - Fatal编程技术网

Java 如何在Spring中使用接口的动态实现?

Java 如何在Spring中使用接口的动态实现?,java,spring,spring-mvc,Java,Spring,Spring Mvc,这个问题是为了回答一个有用的问题 假设我们有一个带有@Controller的Spring应用程序、一个接口和该接口的不同实现 我们希望@Controller根据我们收到的请求使用具有适当实现的接口 这是@Controller: @Controller public class SampleController { @RequestMapping(path = "/path/{service}", method = RequestMethod.GET) public void me

这个问题是为了回答一个有用的问题

假设我们有一个带有@Controller的Spring应用程序、一个接口和该接口的不同实现

我们希望@Controller根据我们收到的请求使用具有适当实现的接口

这是@Controller:

@Controller
public class SampleController {
    @RequestMapping(path = "/path/{service}", method = RequestMethod.GET)
    public void method(@PathVariable("service") String service){
        // here we have to use the right implementation of the interface
    }
}
以下是界面:

public interface SampleInterface {
    public void sampleMethod(); // a sample method
}
以下是一个可能的实现:

public class SampleInterfaceImpl implements SampleInterface {
    public void sampleMethod() {
        // ...
    }
}
public class SampleInterfaceOtherImpl implements SampleInterface {
    public void sampleMethod() {
        // ...
    }
}
还有一个:

以下是一个可能的实现:

public class SampleInterfaceImpl implements SampleInterface {
    public void sampleMethod() {
        // ...
    }
}
public class SampleInterfaceOtherImpl implements SampleInterface {
    public void sampleMethod() {
        // ...
    }
}

下面我将展示我发现的基于请求动态使用其中一个实现的解决方案。

我发现的解决方案就是这个

首先,我们必须在@Controller中自动连接ApplicationContext

@Autowired
private ApplicationContext appContext;
其次,我们必须在接口的实现中使用@Service注释。 在这个例子中,我给他们起了“Basic”和“Other”两个名字

接下来,我们必须获得@Controller中的实现。 这里有一种可能的方法:

@Controller
public class SampleController {
    @Autowired
    private ApplicationContext appContext;

    @RequestMapping(path = "/path/{service}", method = RequestMethod.GET)
    public void method(@PathVariable("service") String service){
        SampleInterface sample = appContext.getBean(service, SampleInterface.class);
        sample.sampleMethod();
    }
}

通过这种方式,Spring在动态上下文中注入了正确的bean,因此通过正确的实现解决了接口。

我解决了这个问题,如下所示:

  • 让接口实现
    支持(…)
    的方法,并将
    列表
    注入控制器
  • 在控制器中创建一个方法
    getCurrentImpl(…)
    ,在
    支持的帮助下解决它
  • 自Spring 4以来,如果您实现
    ordered
    接口或使用注释
    @Order
    ,则自动连线列表将被排序

这样,您就不需要显式地使用ApplicationContext。

我不相信您的解决方案,因为HTTP参数值和bean限定符之间存在隐式链接。无辜地更改bean名称将导致一场灾难,调试起来可能很棘手。我将把所有必要的信息封装在一个地方,以确保任何更改只需要在一个bean中完成:

@Controller
public class SampleController {
    @Autowired
    private SampleInterfaceImpl basic;

    @Autowired
    private SampleInterfaceOtherImpl other;

    Map<String, SampleInterface> services;

    @PostConstruct
    void init() {
        services = new HashMap()<>;
        services.put("Basic", basic);
        services.put("Other", other);
    }

    @RequestMapping(path = "/path/{service}", method = RequestMethod.GET)
    public void method(@PathVariable("service") String service){
        SampleInterface sample = services.get(service);
        // remember to handle the case where there's no corresponding service
        sample.sampleMethod();
    }
}

老实说,我不认为仅仅为了避免编写几行代码而在URL中公开内部实现细节的想法是好的。 @kriger提出的解决方案至少使用键/值方法添加了一个间接步骤

我更愿意创建一个工厂Bean(更面向企业,甚至是一个抽象的工厂模式),它将选择使用哪个具体实现。 通过这种方式,您将能够使用任何自定义逻辑在单独的位置(工厂方法)选择接口。 您将能够将服务URL与具体实现分离(这不是很安全)


如果您正在创建一个非常简单的服务,那么您的解决方案将起作用,但在企业环境中,模式的使用对于确保可维护性和可伸缩性至关重要。

方法的
字符串服务
参数在运行时是否具有Basic或Other的值?您是说服务的调用者在调用时应该传递Basic或Other?是的,在这种情况下,服务变量具有该值之一。虽然服务的调用者知道这些常量有点奇怪,但整个想法可以被有效地操纵+1。如果HTTP参数与应用程序的任何bean都不匹配,您可以尝试捕获BeansException以控制。