什么时候@Dependent范围的CDI bean被销毁,如果你通过Provider.get()获得那个bean?

时间:2014-07-18 10:04:08

标签: java-ee cdi jboss-weld weld

我很难理解CDI 1.0和CDI 1.1中@Dependent范围内的bean的有效生命周期。到目前为止,我的实验得出了以下结论:

  • 未代理@Dependent范围内的bean。
  • @PreDestroy bean被销毁时,不会调用@Dependent方法。
  • Provider.get()始终创建@Dependent bean的新实例。
  • 使用JBoss 6 / CDI 1.0,由@Dependent bean @ApplicationScoped字段创建的Provider<> bean被&#34;泄露&#34;,因为它仍然&#34;属于&#34;到Provider
  • 在使用WELD 2.1.2.Final/CDI 1.1时,我没有看到@Dependent个bean被Provider s泄露的证据(还有!)。 (虽然这可能是因为这些特定的 @Dependent bean是由@Produces方法创建的......!)

我看到CDI 1.1已向destroy()添加了Instance<>方法,可能是为了解决CDI 1.0中的内存泄漏问题。但是Provider<>怎么样?CDI 1.1中是否还会泄漏? (如果确实如此,那么你应该如何使用Provider.get()?)

基本上,我有几个@ApplicationScoped bean / @Singleton EJB,我@Inject Provider字段,我试图使用Provider.get()作为工厂@Dependent@RequestScoped&#34;帮助&#34;豆子。我肯定会 希望这些bean属于&#34;属于&#34;到他们的Provider字段,因为我需要将bean随后收集垃圾:

public void updateStuff() {
    Helper helper = helperProvider.get();
    // use helper...
}

对于我的CDI 1.0应用程序,我正在考虑通过&#34;伪造&#34;来修复内存泄漏。我的Provider代码如下:

provider = new Provider<MyBean>() {
    @Override
    public MyBean get() {
        return getReferenceFor(MyBean.class);
    }
};

private <T> T getReferenceFor(Class<T> type) {
    Bean<?> bean = beanManager.resolve(beanManager.getBeans(type));
    CreationalContext<?> context = beanManager.createCreationalContext(bean);
    try {
        return (T) beanManager.getReference(bean, bean.getBeanClass(), context);
    } finally {
        // Destroy this context - which I don't want to exist anyway.
        // I only need a strong reference to a fully @Inject-ed bean!
        context.release();
    }
}

MyBean是一个@Dependent范围内的bean,没有@PreDestroy方法,只有在我完成它时才需要进行垃圾回收。但是,我无法找到有关Provider s的大量信息,因此无法判断我是否通过这样做来武装某种定时炸弹。

我的一些@Dependent范围内的bean(我仍然通过Provider.get(),btw获得)是由@Produces方法创建的。他们还有被泄露的危险吗?

有人可以告诉我吗? 谢谢,
克里斯

2 个答案:

答案 0 :(得分:3)

来自Weld docs @Dependent beans的生命周期:

  

从不在不同的bean之间共享依赖bean的实例   客户或不同的注射点。它完全是一个依赖   一些其他对象的对象。它是对象实例化的   属于被创建,并在它所属的对象被销毁时被销毁   破坏。

因此@Dependent对象的注入不会自己引入泄漏,根本无需修复。 创造一个短暂的环境只是为了安全起见&#34;完全没必要因为 依赖bean并不依赖于上下文。就注入CDI而言,它们是普通的(强可达的)Java对象 如果您需要实例化逻辑,请将其放在producer method中,并将其放入其中。

答案 1 :(得分:1)

我还没有对您的构造进行测试,但就我个人而言,每当我需要以编程方式查找bean时,我更喜欢CDI.current().select().get()。使用这个构造,我可以确认你将为每个查找获得一个新的@Dependent bean。它不依赖于提供者(在这种情况下是CDI容器)。

请参阅thisthis。我们这里有一个Arquillian测试设置,它将Servlet部署到一个真正的&#34; (或&#34; remote&#34;使用Arquillian术语)服务器并发出HTTP GET请求以找出内部生成的bean。

结果是GlassFish 4.1和WildFly 8.2.0都会在每次查询时为客户端代码提供一个新的@Dependent bean,如果我已正确理解你的问题,那么这正是你想要的。希望它有所帮助!