问题描述
我正在尝试使用 BeanManager 而不是 Instance .select().get() 创建 CDI 托管 bean 的实例.
I'm trying to create instances of CDI managed beans using the BeanManager rather than Instance .select().get().
建议将此作为解决方案,以解决我在 ApplicationScoped bean 及其依赖项的垃圾收集方面遇到的问题 - 请参阅 CDI 应用程序和从属范围可以共同影响垃圾收集? 了解背景和建议的解决方法.
This was suggested as a workaround to an issue I've been having with ApplicationScoped beans and garbage collection of their dependents - see CDI Application and Dependent scopes can conspire to impact garbage collection? for background and this suggested workaround.
如果您在 ApplicationScoped bean 上使用 Instance 编程查找方法,则 Instance 对象和您从中获得的任何 bean 最终都依赖于 ApplicationScoped bean,因此共享它的生命周期.但是,如果您使用 BeanManager 创建 bean,您将拥有 Bean 实例本身的句柄,并且显然可以显式销毁它,我理解这意味着它将被 GCed.
If you use the Instance programmatic lookup method on an ApplicationScoped bean, the Instance object and any beans you get from it are all ultimately dependent on the ApplicationScoped bean, and therefore share it's lifecycle. If you create beans with the BeanManager, however, you have a handle on the Bean instance itself, and apparently can explicitly destroy it, which I understand means it will be GCed.
我目前的做法是在 BeanManagerUtil 类中创建 bean,并返回 Bean、实例和 CreationalContext 的复合对象:
My current approach is to create the bean within a BeanManagerUtil class, and return a composite object of Bean, instance, and 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);
}
}
由此,在调用代码中,我可以获取实际实例,将其放入映射中以供以后检索,并正常使用:
From this, in the calling code, I can then get the actual instance, put it in a map for later retrieval, and use as normal:
private Map<Worker, DestructibleBeanInstance<Worker>> beansByTheirWorkers =
new HashMap<Worker, DestructibleBeanInstance<Worker>>();
...
DestructibleBeanInstance<Worker> destructible =
beanUtils.getDestructibleBeanInstance(Worker.class, workerBindingQualifier);
Worker worker = destructible.getInstance();
...
完成后,我可以查找可破坏的包装器并在其上调用 destroy(),并且应该清理 bean 及其依赖项:
When I'm done with it, I can lookup the destructible wrapper and call destroy() on it, and the bean and its dependents should be cleaned up:
DestructibleBeanInstance<JamWorker> workerBean =
beansByTheirWorkers.remove(worker);
workerBean.destroy();
worker = null;
但是,在运行了几个 worker 并离开我的 JBoss (7.1.0.Alpha1-SNAPSHOT) 20 分钟左右后,我可以看到 GC 发生
However, after running several workers and leaving my JBoss (7.1.0.Alpha1-SNAPSHOT) for 20 minutes or so, I can see GC occurring
2011.002: [GC
Desired survivor size 15794176 bytes, new threshold 1 (max 15)
1884205K->1568621K(3128704K), 0.0091281 secs]
然而,JMAP 直方图仍然显示旧工人及其依赖实例在周围徘徊,未进行 GC.我错过了什么?
Yet a JMAP histogram still shows the old workers and their dependent instances hanging around, unGCed. What am I missing?
通过调试,我可以看到创建的bean的context字段有正确的Worker类型的contextual,没有不完整的实例,也没有parentDependentInstances.它有许多dependentInstances,这些从worker上的字段中可以看出.
Through debugging, I can see that the context field of the bean created has the contextual of the correct Worker type, no incompleteInstances and no parentDependentInstances. It has a number of dependentInstances, which are as expected from the fields on the worker.
Worker 上的其中一个字段实际上是一个 Instance,当我将此字段与通过程序 Instance 查找检索到的 Worker 的字段进行比较时,它们的 CreationalContext 构成略有不同.通过 Instance 查找的 Worker 上的 Instance 字段将 worker 本身置于不完整实例下,而从 BeanManager 检索到的 Worker 上的 Instance 字段则没有.它们都有相同的 parentDependentInstances 和dependentInstances.
One of these fields on the Worker is actually an Instance, and when I compare this field with that of a Worker retrieved via programmatic Instance lookup, they have a slightly different CreationalContext makeup. The Instance field on the Worker looked up via Instance has the worker itself under incompleteInstances, whereas the Instance field on the Worker retrieved from the BeanManager doesn't. They both have identical parentDependentInstances and dependentInstances.
这表明我没有正确反映实例的检索.这是否会导致缺乏破坏?
This suggests to me that I haven't mirrored the retrieval of the instance correctly. Could this be contributing to the lack of destruction?
最后,在调试时,我可以看到 bean.destroy() 在我的 DestructibleBeanInstance.destroy() 中被调用,这会传递到 ManagedBean.destroy,我可以看到依赖对象作为 .release() 的一部分被销毁).但是他们仍然没有得到垃圾收集!
Finally, when debugging, I can see bean.destroy() being called in my DestructibleBeanInstance.destroy(), and this goes through to ManagedBean.destroy, and I can see dependent objects being destroyed as part of the .release(). However they still don't get garbage collected!
对此的任何帮助将不胜感激!谢谢.
Any help on this would be very much appreciated! Thanks.
推荐答案
我会在您粘贴的代码中更改几处.
I'd change a couple of things in the code you pasted.
- 使那个类成为一个普通的java类,没有注入并传入BeanManager.事情可能会以这种方式搞砸.不太可能,但可能.
- 使用
BeanManager.createCreationContext(null)
创建一个新的 CreationalContext,它本质上将为您提供一个依赖范围,您可以在完成后通过调用CreationalContext.release()代码>.
- Make that class a regular java class, no injection and pass in the BeanManager. Something could be messing up that way. It's not likely, but possibly.
- Create a new CreationalContext by using
BeanManager.createCreationContext(null)
which will give you essentially a dependent scope which you can release when you're done by callingCreationalContext.release()
.
假设没有其他 Beans
,您可以通过调用 DestructibleBeanInstance
中已有的 CreationalContext 上的 release 方法,让一切以您想要的方式正常工作> 在那个会弄乱你的应用程序的 CreationalContext 中.先试试看会不会搞砸.
You may be able to get everything to work correctly the way you want by calling the release method on the CreationalContext you already have in the DestructibleBeanInstance
, assuming there's no other Beans
in that CreationalContext that would mess up your application. Try that first and see if it messes things up.
这篇关于如何通过 BeanManager 创建和销毁 CDI(焊接)托管 Bean?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!