Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/401.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何通过BeanManager创建和销毁CDI(Weld)托管bean?_Java_Garbage Collection_Cdi_Managed Bean_Jboss Weld - Fatal编程技术网

Java 如何通过BeanManager创建和销毁CDI(Weld)托管bean?

Java 如何通过BeanManager创建和销毁CDI(Weld)托管bean?,java,garbage-collection,cdi,managed-bean,jboss-weld,Java,Garbage Collection,Cdi,Managed Bean,Jboss Weld,我正在尝试使用BeanManager而不是Instance.select().get()创建CDI托管bean的实例 这被建议作为解决我一直遇到的应用程序处理的bean及其依赖项的垃圾收集问题的一个解决方法-请参阅背景和这一建议的解决方法 如果在ApplicationScoped bean上使用实例编程查找方法,那么实例对象和从中获得的任何bean最终都依赖于ApplicationScoped bean,因此共享它的生命周期。但是,如果使用BeanManager创建Bean,那么Bean实例本身

我正在尝试使用BeanManager而不是Instance.select().get()创建CDI托管bean的实例

这被建议作为解决我一直遇到的应用程序处理的bean及其依赖项的垃圾收集问题的一个解决方法-请参阅背景和这一建议的解决方法

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

我目前的方法是在BeanManagerUtil类中创建bean,并返回bean、instance和CreationContext的复合对象:

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);
    }
}
然而,JMAP柱状图仍然显示了老工人和他们的依赖实例。我错过了什么

通过调试,我可以看到创建的bean的上下文字段具有正确的工作类型的上下文字段,没有不完整的实例和parentDependentInstances。它有许多依赖关系,这与worker上的字段所期望的一样

Worker上的其中一个字段实际上是一个实例,当我将此字段与通过编程实例查找检索的Worker的字段进行比较时,它们的CreationContext构成略有不同。通过实例查找的Worker上的实例字段将Worker本身置于“不完全实例”下,而从BeanManager检索的Worker上的实例字段则没有。它们都具有相同的父依赖关系和依赖关系

这表明我没有正确地镜像实例的检索。这是否会导致缺乏破坏性

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


在此方面的任何帮助都将不胜感激!谢谢。

我想更改您粘贴的代码中的一些内容

  • 使该类成为常规java类,在BeanManager中不进行注入和传递。那样的话,事情可能会搞砸。不太可能,但有可能
  • 使用
    BeanManager.createCreationContext(null)
    创建一个新的CreationContext,这将为您提供一个基本上依赖的作用域,当您调用
    CreationContext.release()
    后,可以释放该作用域
    假设CreationContext中没有其他会打乱应用程序的
    DestructibleBeanInstance
    bean,您可以通过调用CreationContext上的release方法,让一切都按您所希望的方式正常工作。首先尝试一下,看看它是否会把事情搞砸。

    传入null只应该在注入bean以外的类时进行。在您的情况下,您正在注射一颗豆子。然而,我仍然希望GC在这种情况下工作,因此您可以在Weld issue tracker中提交一个JIRA,并提供测试用例和复制步骤吗?

    解决问题的更好方法是使用动态代理来处理bean销毁。通过编程获得bean类实例的代码如下:

    public static <B> B getBeanClassInstance(BeanManager beanManager, Class<B> beanType, Annotation... qualifiers) {
        final B result;
        Set<Bean<?>> beans = beanManager.getBeans(beanType, qualifiers);
        if (beans.isEmpty())
            result = null;
        else {
            final Bean<B> bean = (Bean<B>) beanManager.resolve(beans);
            if (bean == null)
                result = null;
            else {
                final CreationalContext<B> cc = beanManager.createCreationalContext(bean);
                final B reference = (B) beanManager.getReference(bean, beanType, cc);
                Class<? extends Annotation> scope = bean.getScope();
                if (scope.equals(Dependent.class)) {
                    if (beanType.isInterface()) {
                        result = (B) Proxy.newProxyInstance(bean.getBeanClass().getClassLoader(), new Class<?>[] { beanType,
                                Finalizable.class }, new InvocationHandler() {
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                if (method.getName().equals("finalize")) {
                                    bean.destroy(reference, cc);
                                }
                                try {
                                    return method.invoke(reference, args);
                                } catch (InvocationTargetException e) {
                                    throw e.getCause();
                                }
                            }
                        });
                    } else
                        throw new IllegalArgumentException("If the resolved bean is dependent scoped then the received beanType should be an interface in order to manage the destruction of the created dependent bean class instance.");
                } else
                    result = reference;
            }
        }
        return result;
    }
    
    interface Finalizable {
        void finalize() throws Throwable;
    }
    
    publicstaticbgetbeanClassInstance(BeanManager BeanManager、类beanType、注释…限定符){
    最终B结果;
    
    再次感谢您,Jason。我做了您建议的更改,但仍然没有看到任何垃圾收集。但是,当我等待完全GC时,这两种方法都导致对象被收集-成功!以前在完全GC上不是这样。如果您有时间,请您解释一下
    .createCreationContext(null)之间的区别
    .createCreationContext(bean)
    ?我在文档中见过前者用于编写扩展,但我认为这是用于类型的“bean”版本(如果你明白我的意思的话)还不存在?再次感谢您的帮助。根据规范,它为您提供了一个无上下文的bean实例,因此除了创建它所运行的代码部分之外,不应该有任何其他引用它的内容。我向Pete Muir询问了一些额外的见解,但我还没有得到回复。
    DestructibleBeanInstance<JamWorker> workerBean =
            beansByTheirWorkers.remove(worker);
    workerBean.destroy();
    worker = null;
    
    2011.002: [GC
    Desired survivor size 15794176 bytes, new threshold 1 (max 15)
    1884205K->1568621K(3128704K), 0.0091281 secs]
    
    public static <B> B getBeanClassInstance(BeanManager beanManager, Class<B> beanType, Annotation... qualifiers) {
        final B result;
        Set<Bean<?>> beans = beanManager.getBeans(beanType, qualifiers);
        if (beans.isEmpty())
            result = null;
        else {
            final Bean<B> bean = (Bean<B>) beanManager.resolve(beans);
            if (bean == null)
                result = null;
            else {
                final CreationalContext<B> cc = beanManager.createCreationalContext(bean);
                final B reference = (B) beanManager.getReference(bean, beanType, cc);
                Class<? extends Annotation> scope = bean.getScope();
                if (scope.equals(Dependent.class)) {
                    if (beanType.isInterface()) {
                        result = (B) Proxy.newProxyInstance(bean.getBeanClass().getClassLoader(), new Class<?>[] { beanType,
                                Finalizable.class }, new InvocationHandler() {
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                if (method.getName().equals("finalize")) {
                                    bean.destroy(reference, cc);
                                }
                                try {
                                    return method.invoke(reference, args);
                                } catch (InvocationTargetException e) {
                                    throw e.getCause();
                                }
                            }
                        });
                    } else
                        throw new IllegalArgumentException("If the resolved bean is dependent scoped then the received beanType should be an interface in order to manage the destruction of the created dependent bean class instance.");
                } else
                    result = reference;
            }
        }
        return result;
    }
    
    interface Finalizable {
        void finalize() throws Throwable;
    }