Как создавать и уничтожать управляемые компоненты CDI (Weld) с помощью BeanManager?

Я пытаюсь создать экземпляры управляемых компонентов CDI, используя BeanManager, а не Instance .select (). Get ().

Это было предложено в качестве обходного пути к проблеме, с которой я столкнулся с компонентами ApplicationScoped и сборкой мусора их зависимых компонентов - см. Приложения CDI и зависимые области могут вступать в сговор, чтобы повлиять на сборку мусора? для справки, и это предлагаемый обходной путь.

Если вы используете метод программного поиска Instance для bean-компонента ApplicationScoped, объект Instance и любые bean-компоненты, которые вы получаете от него, в конечном итоге зависят от bean-компонента ApplicationScoped и, следовательно, разделяют его жизненный цикл. Однако, если вы создаете bean-компоненты с помощью BeanManager, у вас есть дескриптор самого экземпляра Bean и, по-видимому, вы можете явно уничтожить его, что, как я понимаю, означает, что он будет GCed.

Мой текущий подход состоит в том, чтобы создать bean-компонент в классе BeanManagerUtil и вернуть составной объект Bean, instance и CreationalContext:

public class BeanManagerUtil {

    @Inject private BeanManager beanManager;

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

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

public class DestructibleBeanInstance {

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

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

    public T getInstance() {
        return instance;
    }    

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

Из этого, в вызывающем коде, я могу затем получить фактический экземпляр, поместить его в карте для последующего извлечения и использовать как обычно:

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

Когда я закончу с ней, я могу найти разрушаемую оболочку и вызвать на ней destroy (), а компонент и его зависимые объекты должны быть очищены:

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

Однако после запуска нескольких рабочих и выхода из моего JBoss (7.1.0.Alpha1-SNAPSHOT) в течение 20 минут или около того, я вижу, как происходит сборщик мусора

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

. Однако гистограмма JMAP все еще показывает, что старые рабочие и их зависимые экземпляры слоняются без GCed. Что мне не хватает?

Путем отладки я вижу, что контекстное поле созданного bean-компонента имеет контекстное значение правильного типа Worker, не имеет неполных экземпляров и parentDependentInstances. У него есть несколько зависимых экземпляров, которые, как и ожидалось, зависят от полей рабочего.

Одно из этих полей в Worker'е на самом деле является экземпляром, и когда я сравниваю это поле с полем Worker, полученным с помощью программного поиска Instance, они имеют немного другой состав CreationalContext. В поле Instance для Worker, найденного через Instance, сам воркер находится под неполнымиInstances, тогда как в поле Instance для Worker, полученного из BeanManager, нет. У них обоих одинаковые parentDependentInstances и зависимыеInstances.

Это говорит о том, что я неправильно отразил получение экземпляра. Может ли это быть причиной отсутствия разрушения?

Наконец, при отладке я вижу, что bean.destroy () вызывается в моем DestructibleBeanInstance.destroy (), и это проходит через ManagedBean.destroy, и я вижу зависимые объекты, уничтожаемые как часть .release (). Однако они по-прежнему не собирают мусор!

Мы будем очень признательны за любую помощь в этом вопросе! Спасибо.

7
задан Community 23 May 2017 в 11:50
поделиться