【问题标题】:HK2 and Impls with constructor argumentsHK2 和带有构造函数参数的 Impls
【发布时间】:2014-01-21 12:35:24
【问题描述】:

我使用 HK2 作为 Jersey RESTful API 的一部分。我在一个多租户系统中工作,在我的大多数 API 调用中,租户是一个路径参数。我也有几个 DAO,它们目前在其构造函数中接受tenantId,例如:

public final class WidgetMapper {
    public WidgetMapper(final int tenantId) { .. }
    ..
}

我想使用 HK2 将我的 DAO 提供给我的应用程序的其他层。这样做的正确方法是什么?

  1. 将 DAO 更改为使用 setter 而不是构造函数参数。只有.. ick。 tenantId 是 DAO 所需状态的一部分。

  2. 添加一个抽象层。创建<interface>MapperFactoryMapperFactoryImpl,它有一个无参数的构造函数和一堆getter,例如getWidgetMappergetGizmoMapper。只有..这似乎很麻烦。我宁愿不必维护这些额外的类。

  3. HK2 有什么神奇的方法可以在运行时将该 int 值注入到 WidgetMapper 构造函数中吗?然后我可以将tenantId 注入到映射器中,并将映射器注入到我的其他类中。

  4. ??其他 HK2 魔法?

【问题讨论】:

    标签: java jersey hk2


    【解决方案1】:

    您需要从请求中的路径参数中提取租户ID,因此只要可以为每个请求实例化您的DAO,您就可以实现Factory

    public WidgetMapperFactory implements Factory<WidgetMapper> {
    
        private final ContainerRequestContext containerRequestContext;
    
        @Inject
        public WidgetMapperFactory(ContainerRequestContext containerRequestContext) {
            this.containerRequestContext = containerRequestContext;
        }
    
        public WidgetMapper provide() {
            UriInfo uriInfo = containerRequestContext.getUriInfo();
            List<String> matchedUris = uriInfo.getMatchedURIs();
            int tenantId = 1; // Actually work it out from the matched URIs
            return new WidgetMapper(tenantId);
        }
    
        public void dispose() {
            // Do any clean up you need
        }
    
    }
    

    然后绑定工厂:

    public MyResourceConfig extends ResourceConfig {
    
        public MyResourceConfig() {
            register(new AbstractBinder() {
                @Override
                protected void configure() {
                    bindFactory(WidgetMapperFactory.class).to(WidgetMapper.class).in(RequestScoped.class);
                }
            });
        }
    
    }
    

    然后您可以在Resource 类中注入WidgetMapper,而WidgetMapper 不知道它在Web 服务中的使用情况。

    【讨论】:

      【解决方案2】:

      将 DAO 更改为使用 setter 而不是构造函数参数。 只有.. ick。 tenantId 是 DAO 所需状态的一部分。

      如果您的 DAO 是单例,我看不出这将如何工作(或至少如何干净地完成)。

      这样做的正确方法是什么?

      IMO,我认为最好的方法是 1) 单例 DAO 2) 某种类型的代理,当它们被 HK2 实例化时注入到 DAO 中,然后为当前线程提供正确的租户 ID。

      我可以想到两种方法来做到这一点:

      选项 1:

      我没有尝试过,但我认为您可以可能通过构造函数、私有字段或 setter 将 UriInfo 注入您的 DAO。您可以从 UriInfo 实例中提取当前请求的租户 ID。

      如果我是你,我会为我的 DAO 创建一个抽象类,将 UriInfo 注入私有字段。然后我会提供一个受保护的方法来从 uriInfo.getPathParameters 返回当前租户 ID

      public abstract class AbstractDao {
      
          // jersey/hk2 provides a proxy that references the current thread-bound request
          @Context
          private UriInfo info;
      
          protected int getTenantId()
          {
              // always returns the tenant id for the current request.  TODO: add
              // logic to handle calls that don't have a tenant id.
              return Integer.valueOf(info.getPathParameters.getFirst("tenantId");
          }
      }
      

      选项 2:

      ??其他 HK2 魔法?

      你可以写一个custom injection resolver

      还有一个想法……

      选项 3:

      这个没有直接回答你的问题,因为它没有使用 HK2 将租户 ID 注入 DAO,但我认为值得一提。

      您可以实现自己的ContainerRequestFilter,它获取租户 ID 并将其提供给您应用中的其他组件。

      默认情况下,Jersey 将在解析资源方法之后但在实际调用方法之前调用过滤器。您可以从ContainerRequestContext 获取 UriInfo,获取租户 ID 路径参数,然后将该参数填充到您自己的线程局部变量中。然后,您可以在 DAO 中引用本地线程。同样,我建议在基础 DAO 类中添加一个受保护的方法来封装此逻辑。

      在我的大多数 API 调用中,租户是一个路径参数

      您可以选择使用NameBinding 来控制上述行为。

      如果您愿意,您可以使用常规的 ServletFilter 来实现选项 3。

      注意:

      在我写完这个答案后,我意识到我假设您很乐意扩展 ResourceConfig,您知道如何获取 ServiceLocator 的实例,并且您是 comfortable with adding your own bindings。如果您不是,请告诉我,我将编辑我的答案以提供更多详细信息。

      【讨论】:

      • 约翰,感谢您的回复。 DAO 不是单例,也不会是单例,除非您可以提供令人信服的案例来这样做。选项 1 不好,因为数据访问层不应该知道或关心它正在为 Web API 提供服务。选项 3 是共享静态变量的所有层的多线程等效项。我想我能做到。选项 2 可能有效.. 我现在正在研究它。如果这就是我的想法,我会标记为正确并投票。再次感谢!
      • 听起来选项 2 是最好的。您可能需要将租户 ID 包装在 TenantIdentifier 类中。尝试这样做,然后编写一个Factory&lt;TenantIdentifier&gt; 和一个将 TenantIdentifier 绑定到工厂的 AbstractBinder。注册 binder 后,您应该能够 @Inject TenantIdentifier 的实例。
      • Eric,选项 2 运气好吗?很好奇你是如何解决这个问题的,因为我在我的项目中做了类似的事情。
      猜你喜欢
      • 2021-10-25
      • 2011-11-27
      • 1970-01-01
      • 2018-06-03
      • 1970-01-01
      • 2016-04-16
      • 1970-01-01
      • 1970-01-01
      • 2011-05-07
      相关资源
      最近更新 更多