Tomcat - 异步请求的 WELD 解决方法

标签 tomcat cdi weld2

我有一个使用 WELD 3.0.5 和 RestEasy 3.6.1 在 Tomcat 9 上运行的 REST 应用程序。

对于异步请求,Tomcat 在与触发初始化事件的线程不同的线程中触发请求销毁事件。 在这种情况下,使用 ThreadLocals 的 WELD 不会停用请求上下文,因此不会调用 bean 处理方法。

参见:What do WELD-000225, WELD-000335 and WELD-000715 warnings mean?

Tomcat Bug 57314

我的应用程序依赖于容器生命周期事件来关闭资源和清理资源,因此我需要一种方法让异步请求也能正常工作。我想出的解决方案是添加一个 WebFilter,它在执行链的末尾使当前请求上下文无效。

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws Exception {

    BeanManager beanManager = CDI.current().getBeanManager();
    AlterableContext context = (AlterableContext) beanManager.getContext(RequestScoped.class);
    try {
        chain.doFilter(request, response);
    } finally {
        if (request.isAsyncStarted()) {
            AbstractBoundContext<?> ctxt = (AbstractBoundContext<?>) delegate;
            ctxt.invalidate();
            ctxt.deactivate();
            ctxt.cleanup();
        }
    }
}

这很好地丢弃了 bean 并删除了一些线程局部变量。不幸的是,一些变量仍然与池线程相关联 Tomcat 提示它:

SEVERE: The web application [cdi-weld] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@3d97cd8b]) and a value of type [org.jboss.weld.module.web.servlet.HttpContextLifecycle.Counter] (value [org.jboss.weld.module.web.servlet.HttpContextLifecycle$Counter@43a15b16]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
Nov 02, 2018 10:43:55 AM org.apache.catalina.loader.WebappClassLoaderBase checkThreadLocalMapForLeaks
SEVERE: The web application [cdi-weld] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@21d33dd8]) and a value of type [org.jboss.weld.contexts.AbstractManagedContext.ManagedState] (value [org.jboss.weld.contexts.AbstractManagedContext$ManagedState@2a336421]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
Nov 02, 2018 10:43:55 AM org.apache.catalina.loader.WebappClassLoaderBase checkThreadLocalMapForLeaks
SEVERE: The web application [cdi-weld] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@294b0f79]) and a value of type [org.jboss.weld.module.web.servlet.ConversationContextActivator$$Lambda$555/1676983761] (value [org.jboss.weld.module.web.servlet.ConversationContextActivator$$Lambda$555/1676983761@60fb88ad]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.

我的理解是 ThreadLocals 会针对每个请求被覆盖,所以这不完全是内存泄漏,但我仍然对这个解决方案不是 100% 满意。

有谁知道解决这个问题的更好方法吗?

最佳答案

以下信息不是我尝试过的解决方案,但它是我最好的解决方法。

org.jboss.weld.module.web.servlet.HttpContextLifecycle.Counter 您可能无法修复,或者至少我不知道如何修复。

但其他两个是不同的上下文,您可以像处理请求上下文一样通过停用它们来解决这个问题。

org.jboss.weld.contexts.AbstractManagedContext.ManagedState 您将不得不深入研究这实际上是什么背景。 session 或谈话是我的猜测。尝试使用 BeanManager 来检索您所知道和看到的范围的上下文。一点点调试大有帮助。

org.jboss.weld.module.web.servlet.ConversationContextActivator$$Lambda$555/1676983761 这应该是对话上下文(可能是 LazyHttpConversationContextImpl)。释放该上下文可以使它消失。

关于Tomcat - 异步请求的 WELD 解决方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53119505/

相关文章:

object - 如何获取特定 cdi session 范围 bean 的所有实例

jax-rs - 引用 @ConfigMapping 对象的 CDI 单例的 JAR-RS 过滤器注入(inject)在 Quarkus 中失败

tomcat - 在 Tomcat 上使用带有 Weld CDI 的 Jersey 部署应用程序时出错

java - 多个实体 jar 与增量构建

java - JDBC MySQL 连接在某些 Tomcat 上有效,但在其他 Tomcat 上失败并出现 MySQLNonTransientConnectionException

java - @EJB 依赖注入(inject)在 JBoss AS 6 NullPointerException 中不起作用

java - 使用 Weld 和 Hibernate Validator 进行方法验证

java - 服务层远程握手异常

tomcat - 在 spring boot 嵌入的 tomcat 中禁用 Jar Scan 的 scanManifest