gpt4 book ai didi

java - 将运行时(元)数据传递给 CDI 中的生产者方法

转载 作者:行者123 更新时间:2023-11-30 10:53:01 25 4
gpt4 key购买 nike

我正在维护一个 Multi-Tenancy 应用程序,其中关于请求的特殊元数据( header 、参数)标识特定租户。每个租户在系统中都有覆盖某些默认值的自定义配置。配置来自以 EJB 为前端的缓存增强数据库。要成功查找此类自定义配置,需要 key 和租户标识符。如果租户标识符不存在,则单独使用 key 来检索 key 条目的默认值。

我想从接收这些请求的远程接口(interface)(servlet、web 服务等)中检索此类标识符和设置上下文(例如,将属性放入 EJBContext 中),以便生产者方法可以利用设置适当的 beans 来为每个租户的客户提供服务。理想情况下,在这种情况下,我也希望尽可能合理地支持 CDI 而不是 EJB。

我在考虑以下策略,但我卡住了。

  1. 创建一个 @Config 限定符,以便 CDI 容器解析为配置生产者。
  2. 创建一个@Key(String)配置注解,通过该注解可以获得所需配置条目的查找键。
  3. 创建一个将 InjectionPoint 作为参数的 Producer 方法。 InjectionPoint 允许获取 @Key 注释、目标字段的声明类型以及声明此注入(inject)字段的类(封闭类)。如果 InjectionPoint 允许我获得封闭类的一个实例,那将是一个不错的场景。但是考虑一下,这没有意义,因为在创建/定位并注入(inject)所有依赖项之前,实例还没有准备好。

CDI 不适合这种情况吗?如何最好地实现?

最佳答案

一种可能的解决方案是在请求处理中提取重要的租户值,例如ServletFilter 或一些拦截器并将其存储在 ThreadLocal 持有者中。这仅在两个组件(例如过滤器和 CDI 生产者)在同一线程中执行时才有效 - 因此您可能会遇到 EJB 问题。
您可以在 @Produces 方法中检索租户标识符,并根据 @Key 注释值和租户 ID 返回配置条目。

一些伪解决方案:

ThreadLocal 持有者

public class ThreadLocalHolder {

private static ThreadLocal<String> tenantIdThreadLocal = new ThreadLocal<>();

public static String getTenantId(){
return tenantIdThreadLocal.get();
}
public static void setTenantId(String tenantid){
return tenantIdThreadLocal.set(tenantid);
}
}

租户提取的请求过滤器

@WebFilter(value = "/*")
public class TenantExtractorFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
//obtain tenant id, and store in threadlocal
ThreadLocalHolder.setTenantId(req.getHeader("X-TENANT"));
chain.doFilter(request, response);
}
}

配置条目生产者

public class Producer {

//get a hold of some DAO or other repository of you config
private ConfigRepository configRepo;

@Produces
@Config
public String produceConfigEntry(InjectionPoint ctx) {
Key anno = //get value of @Key annotation from the injection point, bean, property...
String tenantId = ThreadLocalHolder.getTenantId();
// adjust to your needs
return configRepo.getConfigValueForTenant(anno.value(), tenantId);
}
}

如果 ThreadLocal 不是一个选项,请查看 javax.transaction.TransactionSynchronizationRegistry - 它的工作与线程池无关,但显然需要存在事务。

2015 年 12 月 14 日更新
使用请求范围 bean 作为数据持有者的替代方法

RequestScoped 持有者

@RequestScoped
public class RequestDataHolder {
private String tenantId;

public String getTenantId() {
return this.tenantId;
}

public void setTenantId(String tenantId) {
this.tenantId = tenantId;
}
}

网络过滤器

从请求中提取值并将它们存储在我们的 holder 中。

@WebFilter(value = "/*")
public class TenantExtractorFilter implements Filter {

@Inject private RequestDataHolder holder;

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
//obtain tenant id, and store in threadlocal
holder.setTenantId(req.getHeader("X-TENANT"));
chain.doFilter(request, response);
}
}

CDI 制作人使用数据持有者并为注入(inject)点生成预期值。

public class Producer {

//get a hold of some DAO or other repository of you config
private ConfigRepository configRepo;
@Inject
private RequestDataHolder dataHolder;

@Produces
@Config
public String produceConfigEntry(InjectionPoint ctx) {
Key anno = //get value of @Key annotation from the injection point, bean, property...
String tenantId = holder.getTenantId();
// adjust to your needs
return configRepo.getConfigValueForTenant(anno.value(), tenantId);
}
}

我们的 RequestDataHolder bean 可以注入(inject)到任何 CDI、EJB、JAXRS 或 Servlet 组件中,从而允许将变量从 WEB 上下文传递到其他上下文。

注意:此解决方案需要根据 CDI 规范将 CDI 容器与 EJB 和 WEB 容器正确集成。

关于java - 将运行时(元)数据传递给 CDI 中的生产者方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34159078/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com