我正在尝试使用BeanManager而不是实例.select()。get()来创建CDI托管bean的实例。如何通过BeanManager创建和销毁CDI(焊接)托管Bean?
这是建议作为解决方案,我已与ApplicationScoped豆和他们的家属的垃圾回收问题 - 请参阅CDI Application and Dependent scopes can conspire to impact garbage collection?背景和此建议的解决方法。
如果您在ApplicationScoped bean上使用实例编程查找方法,那么Instance对象和从它获取的所有bean最终都依赖于ApplicationScoped bean,因此共享它的生命周期。但是,如果使用BeanManager创建Bean,则您有一个Bean实例本身的句柄,显然可以明确地销毁它,我知道这意味着它将被GCed。
我目前的做法是创建一个BeanManagerUtil类中的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);
}
}
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-快照)20分钟左右的时间,我可以看到GC发生
2011.002: [GC
Desired survivor size 15794176 bytes, new threshold 1 (max 15)
1884205K->1568621K(3128704K), 0.0091281 secs]
然而,一个JMAP直方图仍然显示unGCed,老工人和他们依赖的实例在四处闲逛。我错过了什么?
通过调试,我可以看到创建的bean的上下文字段具有正确的Worker类型的上下文,没有incompleteInstances并且没有parentDependentInstances。它有一些dependentInstances,这与worker的字段中预期的一样。
Worker上的这些字段中的一个实际上是一个实例,当我将该字段与通过编程实例查找检索的Worker的字段进行比较时,它们具有稍微不同的CreationalContext构成。通过Instance查找的Worker上的Instance字段在incompleteInstances下具有worker本身,而从BeanManager中检索的Worker上的Instance字段没有。它们都有相同的parentDependentInstances和dependentInstances。
这表明我没有正确反映实例的检索。这是否可以促成没有破坏?
最后,在调试时,我可以看到在我的DestructibleBeanInstance.destroy()中调用了bean.destroy(),并且这通过ManagedBean.destroy,我可以看到依赖对象被作为.release的一部分销毁()。但是他们仍然没有收集垃圾!
对此的任何帮助将非常感谢!谢谢。
再次感谢Jason。我做了你所建议的更改,但仍未看到任何垃圾回收。然而,当我等待_full_ GC时,两种方法都会导致收集对象 - 成功!以前在完整的GC中情况并非如此。 如果你有时间,请你能解释'.createCreationContext(null)'和'.createCreationContext(bean)'之间的区别吗?我已经在文档中看到前者编写扩展,但是我认为这是为了当bean类型的版本(如果你明白我的意思)不存在的时候?再次感谢您的帮助。 –
根据规范,它为您提供了一个非上下文的bean实例,所以除了创建它的那部分代码之外,不应该有任何其他引用它的东西。我问皮特缪尔一些额外的见解,但我还没有听到。 – LightGuard