【问题标题】:Factory for Spring Beans implementing interfaceSpring Beans 实现接口的工厂
【发布时间】:2021-03-08 13:40:59
【问题描述】:

考虑到一个包含许多实体的项目,我有一个服务需要知道实体的类型才能执行方法。我创造了;

interface Service<T> {
  String myMethod(T entity)
  Class<T> getResponsibility()

例如;

class FooService<Foo> {
  String myMethod(Foo entity) { return 'foo'; }
  Class<Foo> getResponsibility() { return Foo.class }

我想创建一个工厂来返回正确的 Bean(我使用的是 Spring Boot)来使用,这是我定义的:

class ServiceFactory {
  List<Service<?>> services;
  
  @Autowired
  public ServiceFactory(List<Service<?>> services) {
    this.services = services;
  }

  Service getFor(Object entity) {
    // Simplified for comprehension purpose
    return this.services.stream().filter(service -> service.getResponsibility().equals(entity.getClass()).get();
}

这可行,但我有一个(声纳)警告说我不应该“原始”使用Service 作为我的工厂方法的返回类型。实现这一目标的正确方法是什么?使用通配符是另一个警告。

目标是拥有一个返回正确 Bean 的工厂。最初的设计错了吗?

【问题讨论】:

  • 您在调用 get() 时未检查服务是否存在。
  • 是的@SimonMartinelli,真正的代码有一个检查并抛出一个异常,但我觉得它不相关

标签: java spring spring-boot generics


【解决方案1】:

不传递对象,而是传递类本身并将其捕获为方法类型参数:

<T> Service<T> getFor(Class<T> type) {

您仍然会收到警告,因为注入的列表使用了通配符:

@SuppressWarnings("unchecked")
<T> Service<T> getFor(Class<T> type) {
    // Simplified for comprehension purpose
    return (Service<T>) this.services.stream()
            .filter(service -> service.getResponsibility().equals(type))
            .findFirst()
            .get();
}

您最好使用Spring's support for generics,直接注入特定的服务:

@Autowired
Service<Foo> fooService;

【讨论】:

  • 自动装配服务列表使用通配符,它​​如何与方法类型参数共存?您将如何编写方法的主体?
  • 就像你的身体,但有这个过滤谓词filter(service -&gt; type.equals(service.getResponsibility()))。然后在返回之前转换为Service&lt;T&gt;。
  • @Madlemon 这会产生未经检查的演员表警告,我错过了什么吗?
  • 我认为您可以放心地取消该警告。由于getResponsibility() 只能返回服务的确切类型,因此服务类型将始终正确且安全地进行转换。
  • @NathanBruissard 更新了我的答案。确实你是对的,还是有警告的,不过需要服务的责任方法来匹配类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-24
相关资源
最近更新 更多