gpt4 book ai didi

java - 如何通过 BeanManager 创建和销毁 CDI (Weld) Managed Beans?

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:23:45 25 4
gpt4 key购买 nike

我正在尝试使用 BeanManager 而不是 Instance .select().get() 创建 CDI 托管 bean 的实例。

这被建议作为解决我一直遇到的 ApplicationScoped bean 及其依赖项的垃圾收集问题的解决方法 - 请参阅 CDI Application and Dependent scopes can conspire to impact garbage collection?对于背景和这个建议的解决方法。

如果您在 ApplicationScoped bean 上使用 Instance 编程查找方法,则 Instance 对象和您从中获得的任何 bean 最终都依赖于 ApplicationScoped bean,因此共享它的生命周期。但是,如果您使用 BeanManager 创建 bean,那么您将拥有 Bean 实例本身的句柄,并且显然可以显式销毁它,我理解这意味着它将被 GC。

我目前的方法是在 BeanManagerUtil 类中创建 bean,并返回 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(),然后应该清理 bean 及其依赖项:

DestructibleBeanInstance<JamWorker> workerBean =
beansByTheirWorkers.remove(worker);
workerBean.destroy();
worker = null;

但是,在运行几个 worker 并离开我的 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 直方图仍然显示旧 worker 及其相关实例悬而未决,未进行 GC。我错过了什么?

通过调试,可以看到创建的bean的context字段有正确Worker类型的contextual,没有incompleteInstances,也没有parentDependentInstances。它有许多 dependentInstances,这是从 worker 的字段中预期的。

Worker 上的其中一个字段实际上是一个实例,当我将这个字段与通过编程实例查找检索到的 Worker 的字段进行比较时,它们的 CreationalContext 构成略有不同。通过 Instance 查找的 Worker 上的 Instance 字段在 incompleteInstances 下有 worker 本身,而从 BeanManager 检索到的 Worker 上的 Instance 字段则没有。它们都具有相同的 parentDependentInstances 和 dependentInstances。

这表明我没有正确地镜像实例的检索。这会不会导致破坏力不足?

最后,在调试时,我可以看到在我的 DestructibleBeanInstance.destroy() 中调用了 bean.destroy(),这会进入 ManagedBean.destroy,我可以看到相关对象作为 .release( ).然而,他们仍然没有收集垃圾!

如有任何帮助,我们将不胜感激!谢谢。

最佳答案

我会更改您粘贴的代码中的一些内容。

  1. 使该类成为常规 java 类,无注入(inject)并传入 BeanManager。事情可能会那样搞砸。这不太可能,但有可能。
  2. 使用 BeanManager.createCreationContext(null) 创建一个新的 CreationalContext,这实际上会给你一个依赖范围,当你完成调用 CreationalContext.release()

假设没有其他 Bean 在那个会弄乱你的应用程序的 CreationalContext 中。先试试看它是否会把事情搞砸。

关于java - 如何通过 BeanManager 创建和销毁 CDI (Weld) Managed Beans?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8420070/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com