Я пытаюсь создать экземпляры управляемых компонентов CDI, используя BeanManager, а не Instance .select (). Get ().
Это было предложено в качестве обходного пути к проблеме, с которой я столкнулся с компонентами ApplicationScoped и сборкой мусора их зависимых элементов - см. Область применения и зависимые области применения CDI могут влиять на сборку мусора? для фона, и это предложил обходной путь.
Если вы используете метод программного поиска Instance для bean-компонента ApplicationScoped, то объект Instance и любые бины, которые вы получаете от него, все в конечном итоге зависят от bean-компонента ApplicationScoped и, следовательно, совместно используют его жизненный цикл. Однако, если вы создаете bean-компоненты с BeanManager, у вас есть дескриптор самого экземпляра Bean, и, очевидно, вы можете явно уничтожить его, что, как я понимаю, означает, что он будет GCed.
Мой текущий подход заключается в создании компонента внутри класса BeanManagerUtil и возвращении составного объекта Bean, instance и 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);
}
}
Исходя из этого, в коде вызова я могу получить фактический экземпляр, поместить его в карту для последующего поиска и использовать как обычно:
private Map<Worker, DestructibleBeanInstance<Worker>> beansByTheirWorkers =
new HashMap<Worker, DestructibleBeanInstance<Worker>>();
...
DestructibleBeanInstance<Worker> destructible =
beanUtils.getDestructibleBeanInstance(Worker.class, workerBindingQualifier);
Worker worker = destructible.getInstance();
...
Когда я покончу с этим, я смогу найти разрушаемую оболочку и вызвать для нее метод destroy (), а бин и его зависимые объекты должны быть очищены:
DestructibleBeanInstance<JamWorker> workerBean =
beansByTheirWorkers.remove(worker);
workerBean.destroy();
worker = null;
Однако, после запуска нескольких рабочих и оставления моего JBoss (7.1.0.Alpha1-SNAPSHOT) или около 20 минут, я вижу, что происходит GC
2011.002: [GC
Desired survivor size 15794176 bytes, new threshold 1 (max 15)
1884205K->1568621K(3128704K), 0.0091281 secs]
И все же гистограмма JMAP по-прежнему показывает, что старые рабочие и их зависимые экземпляры слоняются без дела. Чего мне не хватает?
Посредством отладки я вижу, что контекстное поле созданного bean-компонента имеет контекстный контекст с правильным типом Worker, в котором нет incompleteInstances и parentDependentInstances. Он имеет несколько зависимых экземпляров, которые ожидаются от полей на работнике.
Одним из этих полей в Worker на самом деле является Instance, и когда я сравниваю это поле с полем Worker, полученным с помощью программного поиска Instance, они имеют немного другую структуру CreationalContext. Поле Instance на Worker, просмотренном с помощью Instance, имеет самого работника в незаконченных экземплярах, а поле Instance на Worker, полученное из BeanManager, - нет. Они оба имеют идентичные parentDependentInstances и зависимые экземпляры.
Это говорит о том, что я неправильно отразил получение экземпляра. Может ли это способствовать отсутствию разрушений?
Наконец, при отладке я вижу, как bean.destroy () вызывается в моем DestructibleBeanInstance.destroy (), и это проходит к ManagedBean.destroy, и я вижу, как зависимые объекты уничтожаются как часть .release ( ). Однако они все еще не собирают мусор!
Любая помощь по этому вопросу будет принята с благодарностью! Спасибо.