我正在嘗試使用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