将 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。如果您不是,请告诉我,我将编辑我的答案以提供更多详细信息。