Я пытаюсь создать экземпляры управляемых компонентов 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 (). Однако они по-прежнему не собирают мусор!
Мы будем очень признательны за любую помощь в этом вопросе! Спасибо.