如何通过BeanManager创建和销毁CDI(Weld)托管Bean? [英] How to create and destroy CDI (Weld) Managed Beans via the BeanManager?

查看:190
本文介绍了如何通过BeanManager创建和销毁CDI(Weld)托管Bean?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用BeanManager而不是实例.select()。get()来创建CDI托管bean的实例。

这个建议是解决我在ApplicationScoped bean和其依赖项的垃圾回收时遇到的一个问题 - 请参阅 CDI应用程序和相关作用域可以共同影响垃圾回收?建议的解决方法。

如果您在ApplicationScoped bean上使用Instance编程式查找方法,那么Instance对象和从它获取的所有Bean最终都依赖于ApplicationScoped bean,因此共享它的生命周期。但是,如果使用BeanManager创建Bean,则您有一个Bean实例本身的句柄,显然可以明确地销毁它,我知道这意味着它将被GCed。



我现在的方法是在BeanManagerUtil类中创建bean,并返回Bean,实例和CreationalContext的组合对象:

  public class BeanManagerUtil {

@Inject private BeanManager beanManager;

@SuppressWarnings(unchecked)
public< T> DestructibleBeanInstance< T> getDestructibleBeanInstance(final Class< T> type,
final Annotation ... qualifiers){

DestructibleBeanInstance< T> result = null;
Bean< T> bean =(Bean< T>)beanManager.resolve(beanManager.getBeans(type,qualifiers));
if(bean!= null){
CreationalContext< T> creationalContext = beanManager.createCreationalContext(bean);
if(creationalContext!= null){
T instance = bean.create(creationalContext);
result = new DestructibleBeanInstance< T>(instance,bean,creationalContext);
}
}
返回结果;
}
}

public class DestructibleBeanInstance< T> {

私人T实例;
私人Bean< T>豆;
private CreationalContext< T>上下文;

public DestructibleBeanInstance(T实例,Bean T,bean,CreationalContext< T>上下文){
this.instance = instance;
this.bean = bean;
this.context = context;
}

public T getInstance(){
return instance;
}

public void destroy(){
bean.destroy(instance,context);




$ b $ p
$ b

从这个角度来看,在调用代码中,

  private Map< Worker,DestructibleBeanInstance< / p>工作者GT;> beansByTheirWorkers = 
new HashMap< Worker,DestructibleBeanInstance< Worker>>();
...
DestructibleBeanInstance< Worker> destructible =
beanUtils.getDestructibleBeanInstance(Worker.class,workerBindingQualifier);
Worker worker = destructible.getInstance();
...

当我完成它时,我可以查找可破坏的包装器并在其上调用destroy(),并清理bean及其依赖项:

  DestructibleBeanInstance< JamWorker> workerBean = 
beansByTheirWorkers.remove(worker);
workerBean.destroy();
worker = null;

然而,在运行几个工作者并离开我的JBoss(7.1.0.Alpha1-SNAPSHOT)20分钟左右,我可以看到发生GC

  2011.002:[GC 
希望的幸存者大小15794176字节,新的阈值1 (最大15)
1884205K-> 1568621K(3128704K),0.0091281秒]

然而,一个JMAP直方图仍然显示老工人和他们的依赖实例挂在身边,unGCed。我错过了什么?



通过调试,我可以看到创建的bean的上下文字段具有正确的Worker类型的上下文,没有incompleteInstances,也没有parentDependentInstances。它有一些dependentInstances,这与worker的字段中预期的一样。

Worker中的其中一个字段实际上是一个实例,当我将该字段与通过编程实例查找检索到的字段进行比较时,它们具有稍微不同的CreationalContext化妆。通过Instance查找的Worker上的Instance字段在incompleteInstances下具有worker本身,而从BeanManager中检索的Worker上的Instance字段没有。它们都有相同的parentDependentInstances和dependentInstances。



这表明我没有正确地镜像实例检索。这可能是造成销毁不足的原因吗?



最后,在调试时,我可以看到在我的DestructibleBeanInstance.destroy()中调用了bean.destroy()通过ManagedBean.destroy,我可以看到依赖对象被作为.release()的一部分销毁。然而,他们仍然没有收集垃圾!



任何帮助都会非常感谢!感谢。

解决方案

我会在您粘贴的代码中更改一些内容。


  1. 使这个类成为一个普通的java类,不需要注入并传入BeanManager。有些东西可能会搞砸了。这不太可能,但可能。

  2. 通过使用 BeanManager.createCreationContext(null)创建一个新的CreationalContext,通过调用 CreationalContext.release()完成调试。

您可以通过调用CreationalContext上的release方法让所有内容按照您的方式正确工作 DestructibleBeanInstance ,假定该CreationalContext中没有其他的 Beans 会导致应用程序混乱。先尝试一下,看看是否会让事情发生混乱。


I'm trying to create instances of CDI managed beans using the BeanManager rather than Instance .select().get().

This was suggested as a workaround to an issue I've been having with ApplicationScoped beans and garbage collection of their dependents - see CDI Application and Dependent scopes can conspire to impact garbage collection? for background and this suggested workaround.

If you use the Instance programmatic lookup method on an ApplicationScoped bean, the Instance object and any beans you get from it are all ultimately dependent on the ApplicationScoped bean, and therefore share it's lifecycle. If you create beans with the BeanManager, however, you have a handle on the Bean instance itself, and apparently can explicitly destroy it, which I understand means it will be GCed.

My current approach is to create the bean within a BeanManagerUtil class, and return a composite object of Bean, instance, and CreationalContext:

public class BeanManagerUtil {

    @Inject private BeanManager beanManager;

    @SuppressWarnings("unchecked")
    public <T> DestructibleBeanInstance<T> getDestructibleBeanInstance(final Class<T> type,
            final Annotation... qualifiers) {

        DestructibleBeanInstance<T> result = null;
        Bean<T> bean = (Bean<T>) beanManager.resolve(beanManager.getBeans(type, qualifiers));
        if (bean != null) {
            CreationalContext<T> creationalContext = beanManager.createCreationalContext(bean);
            if (creationalContext != null) {
                T instance = bean.create(creationalContext);
                result = new DestructibleBeanInstance<T>(instance, bean, creationalContext);
            }
        }
        return result;
    }
}

public class DestructibleBeanInstance<T> {

    private T instance;
    private Bean<T> bean;
    private CreationalContext<T> context;

    public DestructibleBeanInstance(T instance, Bean<T> bean, CreationalContext<T> context) {
        this.instance = instance;
        this.bean = bean;
        this.context = context;
    }

    public T getInstance() {
        return instance;
    }    

    public void destroy() {
        bean.destroy(instance, context);
    }
}

From this, in the calling code, I can then get the actual instance, put it in a map for later retrieval, and use as normal:

private Map<Worker, DestructibleBeanInstance<Worker>> beansByTheirWorkers =
    new HashMap<Worker, DestructibleBeanInstance<Worker>>();
...
DestructibleBeanInstance<Worker> destructible =
        beanUtils.getDestructibleBeanInstance(Worker.class, workerBindingQualifier);
Worker worker = destructible.getInstance();
...

When I'm done with it, I can lookup the destructible wrapper and call destroy() on it, and the bean and its dependents should be cleaned up:

DestructibleBeanInstance<JamWorker> workerBean =
        beansByTheirWorkers.remove(worker);
workerBean.destroy();
worker = null;

However, after running several workers and leaving my JBoss (7.1.0.Alpha1-SNAPSHOT) for 20 minutes or so, I can see GC occurring

2011.002: [GC
Desired survivor size 15794176 bytes, new threshold 1 (max 15)
1884205K->1568621K(3128704K), 0.0091281 secs]

Yet a JMAP histogram still shows the old workers and their dependent instances hanging around, unGCed. What am I missing?

Through debugging, I can see that the context field of the bean created has the contextual of the correct Worker type, no incompleteInstances and no parentDependentInstances. It has a number of dependentInstances, which are as expected from the fields on the worker.

One of these fields on the Worker is actually an Instance, and when I compare this field with that of a Worker retrieved via programmatic Instance lookup, they have a slightly different CreationalContext makeup. The Instance field on the Worker looked up via Instance has the worker itself under incompleteInstances, whereas the Instance field on the Worker retrieved from the BeanManager doesn't. They both have identical parentDependentInstances and dependentInstances.

This suggests to me that I haven't mirrored the retrieval of the instance correctly. Could this be contributing to the lack of destruction?

Finally, when debugging, I can see bean.destroy() being called in my DestructibleBeanInstance.destroy(), and this goes through to ManagedBean.destroy, and I can see dependent objects being destroyed as part of the .release(). However they still don't get garbage collected!

Any help on this would be very much appreciated! Thanks.

解决方案

I'd change a couple of things in the code you pasted.

  1. Make that class a regular java class, no injection and pass in the BeanManager. Something could be messing up that way. It's not likely, but possibly.
  2. Create a new CreationalContext by using BeanManager.createCreationContext(null) which will give you essentially a dependent scope which you can release when you're done by calling CreationalContext.release().

You may be able to get everything to work correctly the way you want by calling the release method on the CreationalContext you already have in the DestructibleBeanInstance, assuming there's no other Beans in that CreationalContext that would mess up your application. Try that first and see if it messes things up.

这篇关于如何通过BeanManager创建和销毁CDI(Weld)托管Bean?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆