【问题标题】:Spring @Controller and RequestMapping calling different services depending on a given parameterSpring @Controller 和 RequestMapping 根据给定参数调用不同的服务
【发布时间】:2014-05-12 13:39:41
【问题描述】:

假设我有这个代码:

@Controller
@RequestMapping("/something")
public class SomeController {
    @Autowired
    private SomeService aService;

    @RequestMapping("/doStuff")
    public void doStuff(@RequestParam("type") String type) {
        aService.doStuff();
    }
}

在我的应用程序中,我需要根据指定的类型调用特定的服务。所有服务都实现相同的接口。如果我理解正确 SomeService 不能是一个接口。每次完成新请求时,我都可以使用服务工厂并根据类型实例化服务,但这看起来效率不高。

或者,我可以为每种不同类型的服务使用不同的控制器(并在 REST URI 中编码类型),但这意味着很多代码重复,因为所有服务基本上都实现相同的接口。

我的问题是,假设被调用的服务依赖于传递的参数,那么这种情况下采用的最佳模式是什么?

【问题讨论】:

  • 如果我理解正确SomeService不可能是一个接口错了,它可以是一个接口,事实上它应该是,Spring会用一个类的实例注入它实现,或者只是从 BeanFactory 恢复所需的实例。

标签: java spring


【解决方案1】:

类似于 RC. 的回答,而不是使用 Map 并由您添加值,只需让 Spring BeanFactory 为您处理:

@Controller
@RequestMapping("/something")
public class SomeController {
    @Autowired
    private BeanFactory beanFactory;

    @RequestMapping("/doStuff")
    public void login(@RequestParam("type") String type) {
        SomeService aService = (SomeService)beanFactory.getBean(type);
        aService.doStuff();
    }
}

【讨论】:

  • 我最终采用了这个,它类似于我之前在服务工厂尝试过的来自 RC 的那个,但与BeanFactory 方法相比,我什么也没得到,而且我正在努力解决 bean 实例化问题.感谢大家的精彩回答,你们完成了我的一天。
【解决方案2】:

你可以在这里使用地图,沿着这个:

@Controller
@RequestMapping("/something")
public class SomeController {
    @Autowired
    private SomeService someService;

    @Autowired
    private SomeOtherService someOtherService;

    // ...

    private final Map<String, ServiceCommonInterface> serviceMap = new HashMap<>();

    @PostConstruct
    private void postConstruct() {
        serviceMap.put(typeForSomeService, someService);
        serviceMap.put(typeForSomeOtherService, someOtherService);
    }

    @RequestMapping("/doStuff")
    public void login(@RequestParam("type") String type) {
        // TODO: ensure type is correct (an enum might be handy here)
        serviceMap.get(type).doStuff();
    }
}

或者更好,如 cmets 中所述,您可以利用限定符:

@Controller
@RequestMapping("/something")
public class SomeController {
    @Autowired
    private ApplicationContext applicationContext;

    @RequestMapping("/doStuff")
    public void login(@RequestParam("type") String type) {
        // TODO: ensure type is a correct bean name
        applicationContext.getBean(type, ServiceCommonInterface.class).doStuff();
    }
}

【讨论】:

  • 这就是我想要的。或者,创建一个注入所有服务并生成Map 的bean,而不是直接映射。
  • 是的,我正在阅读您的评论并想“该死的我只能使用限定符”,地图是弹簧上下文
【解决方案3】:

根据您希望支持的类型数量,我看到了两个选项。

1) 如您所述,在工厂中自动装配,并根据需要懒惰地创建每个服务。如果服务是无状态的,您可以在创建后保留对对象的引用,因此每种类型只需要创建一次。

2) 在 Spring Map 中自动装配,键是您的类型,值是要使用的正确服务。然后当您收到类型时,可以为您的地图检索正确的服务实现。

例如地图:http://www.mkyong.com/spring/spring-collections-list-set-map-and-properties-example/ 或查看How to inject a Map<String, List> in java springs?

这两个都需要你为你的服务创建一个接口,你说这是可能的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    相关资源
    最近更新 更多