【问题标题】:programmatic conversation lookup程序化对话查找
【发布时间】:2012-08-28 17:32:18
【问题描述】:

是否有可能仅知道当前的thread 是用于处理与所需对话关联的CDI requestCDI conversation 实例?如果可能,那怎么做?

具体来说,我想做的是这样的:

@ConversationScoped
public class UnitOfWork {...}

public class Client {
    @Inject transient UnitOfWork uof;
...
}

public class Room {
    @Inject transient UnitOfWork uof;
...
}

但是使用编程机制来初始化uof 实例变量而不是应用@Inject 注释(因为ClientRoom 是实体并且它们不支持注入)。
我已经尝试通过以下静态方法获得的BeanManager 注入UnitOfWork

public static <B> B getManagedBean(Class<B> type, Annotation... qualifiers) {
    try {
        BeanManager beanManager = InitialContext.doLookup("java:comp/BeanManager");
        Set<Bean<?>> beans = beanManager.getBeans(type, qualifiers);
        Bean<B> bean = (Bean<B>) beanManager.resolve(beans);
        CreationalContext<B> cc = beanManager.createCreationalContext(bean);
        return bean.create(cc);
    } catch (NamingException e) {
        throw new RuntimeException("", e);
    }
}

但问题是通过上述方法给出的 bean 是新的(每次调用都会给出一个新实例),我需要 ClientRoom 共享相同的会话范围实例 UnitOfWork

【问题讨论】:

    标签: jakarta-ee cdi lookup conversation-scope


    【解决方案1】:

    对不起,不是一个真正的答案,但在评论中写得太多了:

    实体不支持依赖注入是有原因的——主要是因为它们的生命周期与托管 bean 的生命周期是分离的。

    虽然我肯定会在实体中看到 DI 的用例,但我会加倍(和三倍)检查这种方法的好处是否大于风险。您可能会发现自己在某种二级缓存地狱中破解持久性上下文;)

    【讨论】:

    • 如果所有注入的属性都是瞬态的,您提到的风险是否适用?
    • 这只是一方面。我认为最大的问题在于您对实体的创建/缓存/序列化没有太多控制或影响。这对于您的用例来说可能没问题,但它肯定会令人困惑 - 如果不是错误的话。
    • @Entity类的实例仍然是由持久化单元通过javax.persistence.Query实例等的标准方式创建的。我的方法的不同之处在于它们不是简单的 POJO,而是具有行为的对象。并且注入的属性都是瞬态的,并且在服务定位器的帮助下懒惰地初始化。您需要解决的问题是在服务定位器内部。我需要它能够获取与请求关联的Conversation 实例,该请求是当前Thread 的所有者。
    • 我知道实体本身将缺乏 CDI 的好处,但注入的依赖项不会。因此,当实体必须执行需要 CDI 的操作时,它将将此功能委托给注入的对象。我错过了什么吗?
    【解决方案2】:

    答案非常接近,但我忽略了它。 是的,可以通过 BeanManager 获取任何活动上下文(与当前线程关联的上下文)包含的任何 bean 的 bean 类实例。 这个方法可以完成工作:

    public static <B> B getContextualBeanInstance(Class<B> type, Annotation... qualifiers) {
        try {
            BeanManager beanManager = InitialContext.doLookup("java:comp/BeanManager");
            Set<Bean<?>> beans = beanManager.getBeans(type, qualifiers);
            Bean<?> bean = beanManager.resolve(beans);
            CreationalContext<?> cc = beanManager.createCreationalContext(bean);
            return (B) beanManager.getReference(bean, type, cc);
        } catch (NamingException e) {
            throw new RuntimeException("", e);
        }
    }
    

    与我在问题帖子中提到的方法的唯一区别是这个使用BeanManager#getReference(..)而不是Bean#create(..)

    如果要支持参数化 bean 类型,请将 type 参数的类型从 Class&lt;B&gt; 更改为 Type

    如果 bean 是 @Dependent 作用域的,则应注意销毁 bean 类实例以避免内存泄漏。 Here我解释了如何做得很好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-22
      • 1970-01-01
      • 2019-03-01
      • 1970-01-01
      • 2021-05-15
      • 1970-01-01
      • 2015-12-17
      • 1970-01-01
      相关资源
      最近更新 更多