将 DAO 更改为使用 setter 而不是构造函数参数。只有.. ick。tenantId 是 DAO 所需状态的一部分。
如果您的 DAO 是单例,我看不出这将如何工作(或至少如何干净地完成)。
这样做的正确方法是什么?
IMO,我认为最好的方法是拥有 1) 单例 DAO 2) 某种类型的代理,当它们由 HK2 实例化时注入到 DAO 中,然后为当前线程提供正确的租户 ID。
我可以想到两种方法来做到这一点:
选项1:
我还没有尝试过,但我认为您可能可以通过构造函数、私有字段或设置器将 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魔术?
您可以编写自定义注入解析器。
还有一个想法...
选项 3:
这个没有直接回答你的问题,因为它不使用 HK2 将租户 ID 注入 DAO,但我认为值得一提。
您可以实现自己的ContainerRequestFilter来获取租户 id 并将其提供给应用程序中的其他组件。
默认情况下,Jersey 将在解析资源方法之后但在实际调用方法之前调用过滤器。您可以从ContainerRequestContext获取 UriInfo ,获取租户 ID 路径参数,然后将该参数填充到您自己的线程局部变量中。然后,您可以在 DAO 中引用本地线程。同样,我建议在基础 DAO 类中添加一个受保护的方法来封装这个逻辑。
在我的大多数 API 调用中,租户是一个路径参数
或者,您可以使用NameBinding来控制上述行为。
如果您愿意,您可以使用常规的 ServletFilter 来实现选项 3。
笔记:
在我写完这个答案之后,我意识到我假设您对扩展ResourceConfig很满意,您知道如何获取ServiceLocator的实例,并且您对添加自己的 bindings 很满意。如果不是,请告诉我,我将编辑我的答案以提供更多详细信息。