Tomcat - WELD обходной путь для асинхронных запросов

У меня есть приложение REST, реализованное с помощью WELD 3.0.5 и RestEasy 3.6.1, работающее на Tomcat 9.

Для асинхронных запросов Tomcat запускает событие уничтожения запроса в другом потоке, чем тот, который инициировал инициализированное событие. В этом случае WELD, который использует ThreadLocals, не деактивирует контекст запроса и, как следствие, методы удаления бина не вызываются.

См.: Что означают предупреждения WELD-000225, WELD-000335 и WELD-000715?

и 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();
        }
    }
}

Это очень хорошо отбрасывает компоненты и удаляет некоторые локальные переменные потока. К сожалению, некоторые переменные остаются привязанными к объединенному потоку, и 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% доволен этим решением.

Кто-нибудь знает лучший способ обойти эту проблему?

1 ответ

Приведенная ниже информация не является решением, которое я пробовал, но это мой лучший пример того, как вы можете исправить некоторые из них.

org.jboss.weld.module.web.servlet.HttpContextLifecycle.Counter вы, вероятно, не сможете исправить, или, по крайней мере, я не знаю как.

Но два других - это разные контексты, и вы можете решить эту проблему, деактивировав их, как вы сделали это с контекстом запроса.

org.jboss.weld.contexts.AbstractManagedContext.ManagedStateВам придется копаться в том, в каком контексте это на самом деле. Сессия или разговор - мое предположение. Попробуйте использовать BeanManager чтобы найти контексты для областей вы знаете, там и посмотреть. Немного отладки проходит долгий путь.

org.jboss.weld.module.web.servlet.ConversationContextActivator$$Lambda$555/1676983761 Это должен быть контекст разговора (возможно, LazyHttpConversationContextImpl). Освобождение этого контекста может заставить это уйти.

Другие вопросы по тегам