Несколько асинхронный контекст в сервлете не работает

Я пытаюсь отработать несколько цепочек асинхронных запросов в сервлетах, и я сталкиваюсь со странным поведением. Не уверен, имеет ли это отношение к коту.

Итак, вот сценарий. У меня есть простое J2EE maven веб-приложение.

У меня есть два сервлета и фильтр. Я пометил их всех с помощью asyncSupported=true. Когда я нажимаю на ссылку в JSP, первый сервлет действительно принимает запрос и порождает новый рабочий поток, используя AsyncContext. Затем рабочий поток записывает что-то в ответ, фиксирует его (как я узнал, это допустимо для асинхронной обработки в сервлетах) и затем отправляет запрос другому сервлету. До этого момента все работает нормально.

Предполагается, что второй сервлет порождает второй рабочий поток, а затем планировалось сделать диспетчеризацию вызова второго рабочего потока (поскольку я также пытался практиковать вызов без параметров для dispatch()), чтобы вернуться ко второму сервлету, который назвал это. Тем не менее, я получаю сообщение об ошибке ниже при вызове startAsync() на втором сервлете

 06-Apr-2018 19:04:48.128 WARNING [RMI TCP Connection(5)-127.0.0.1] org.apache.catalina.startup.ContextConfig.validateSecurityRoles Security role name [authSupervisor] used in an <auth-constraint> without being defined in a <security-role>
06-Apr-2018 19:04:48.261 INFO [RMI TCP Connection(5)-127.0.0.1] com.kingshuk.listeners.MyServletContextListener.contextInitialized The servlet class com.kingshuk.servlets.MyAppDynamicServlet is now being registered
06-Apr-2018 19:05:09.025 WARNING [http-nio-8080-exec-8] org.apache.catalina.connector.Request.startAsync Unable to start async because the following classes in the processing chain do not support async []
 java.lang.IllegalStateException: A filter or servlet of the current chain does not support asynchronous operations.
    at org.apache.catalina.connector.Request.startAsync(Request.java:1636)
    at org.apache.catalina.connector.Request.startAsync(Request.java:1628)
    at org.apache.catalina.connector.RequestFacade.startAsync(RequestFacade.java:1043)
    at javax.servlet.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:378)
    at com.kingshuk.servlets.BiggestAsyncSecondServlet.doGet(BiggestAsyncSecondServlet.java:23)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at com.kingshuk.filters.AsyncRequestLoggingFilter.doFilter(AsyncRequestLoggingFilter.java:25)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:712)
    at org.apache.catalina.core.ApplicationDispatcher.doDispatch(ApplicationDispatcher.java:633)
    at org.apache.catalina.core.ApplicationDispatcher.dispatch(ApplicationDispatcher.java:601)
    at org.apache.catalina.core.AsyncContextImpl$AsyncRunnable.run(AsyncContextImpl.java:566)
    at org.apache.catalina.core.AsyncContextImpl.doInternalDispatch(AsyncContextImpl.java:352)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:196)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:494)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:651)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:235)
    at org.apache.coyote.AbstractProcessor.dispatch(AbstractProcessor.java:228)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:754)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1376)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)

Ниже приведены все связанные файлы

Фильтр

@WebFilter(filterName = "AsyncRequestLoggingFilter",
        urlPatterns = {"/asyncServlet", "/biggestAsyncRequestTest", "/biggestAsyncRequestTest2"},
        asyncSupported = true,
        dispatcherTypes = {DispatcherType.ASYNC, DispatcherType.REQUEST})
public class AsyncRequestLoggingFilter implements Filter {

    public void init(FilterConfig config) throws ServletException {
        System.out.println("<<AsyncRequestLoggingFilter>> Initializing the Filter");
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws ServletException, IOException {
        if (DispatcherType.ASYNC.equals(req.getDispatcherType())) {
            System.out.println("<<AsyncRequestLoggingFilter>> This is BEFORE calling the doFilter during the ASYNC dispatching");
        } else {
            System.out.println("<<AsyncRequestLoggingFilter>> This is BEFORE calling the doFilter");
        }

        chain.doFilter(req, resp);

        if (DispatcherType.ASYNC.equals(req.getDispatcherType())) {
            System.out.println("<<AsyncRequestLoggingFilter>> This is AFTER returning from  the doFilter call after the ASYNC dispatching");
        } else {
            System.out.println("<<AsyncRequestLoggingFilter>> This is AFTER returning from  the doFilter call");
        }
    }

    public void destroy() {
        System.out.println("<<AsyncRequestLoggingFilter>> Destroying the Filter");
    }

}

Первый сервлет

@WebServlet(name = "BiggestAsyncFirstServlet",
            urlPatterns = "/biggestAsyncRequestTest",
            asyncSupported = true)
public class BiggestAsyncFirstServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        AsyncContext asyncContext = request.startAsync();

        asyncContext.setTimeout(10000);

        asyncContext.addListener(asyncContext.createListener(BiggestAsyncContextListener.class));

        //asyncContext.start(new BiggestAsyncFirstWorkerThread());


        /*
           Step 5.Get the reference to the thread pool that was created in the context listener class
           when the app was deployed
        */
        ThreadPoolExecutor executor = (ThreadPoolExecutor) request.getServletContext().getAttribute("executor");

        /*
           Step 6.Actually creating the worker thread
           and kick starting the thread by calling the run method of the class implementing the runnable interface.
         */
        executor.execute(new BiggestAsyncFirstWorkerThread(asyncContext));

        System.out.println("Hi I'm the servlet " + getServletName() + " and my job is done");

    }
}

Второй сервлет

@WebServlet(name = "BiggestAsyncSecondServlet",
            urlPatterns = "/biggestAsyncRequestTest2",
            asyncSupported = true)
public class BiggestAsyncSecondServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        AsyncContext asyncContext = request.startAsync();

        //asyncContext.setTimeout(10000);

        //asyncContext.createListener(BiggestAsyncContextListener.class);

        //asyncContext.start(new BiggestAsyncFirstWorkerThread());


        /*
           Step 5.Get the reference to the thread pool that was created in the context listener class
           when the app was deployed
        */
        ThreadPoolExecutor executor = (ThreadPoolExecutor) request.getServletContext().getAttribute("executor");

        /*
           Step 6.Actually creating the worker thread
           and kick starting the thread by calling the run method of the class implementing the runnable interface.
         */
        executor.execute(new BiggestAsyncSecondWorkerThread(asyncContext));

        System.out.println("Hi I'm the servlet " + getServletName() + " and my job is done");
    }
}

Первый рабочий поток

public class BiggestAsyncFirstWorkerThread implements Runnable {
    private AsyncContext context;

    public BiggestAsyncFirstWorkerThread(AsyncContext context) {
        this.context = context;
    }


    @Override
    public void run() {
        //The idea is to write something to the response and then dispatch.
        try {
            AsyncRequestProcessor.waitingTime(6000);
            PrintWriter writer = context.getResponse().getWriter();

            writer.print("<html>\n" +
                    "<head>\n" +
                    "    <title>User login</title>\n" +
                    "\n" +
                    "    <link rel=\"stylesheet\" type=\"text/css\" href=\"/" +
                    context.getRequest().getServletContext().getServletContextName() + "/style/master_css.css\">\n" +
                    "\n" +
                    "\n" +
                    "</head>");
            writer.print("<body>\n" +
                    "<div id=\"allcontent\">");
            context.getRequest().getRequestDispatcher("pages/common/header.jsp").
                    include(context.getRequest(), context.getResponse());
            writer.print(" <div id=\"actual_content\">");


            context.getResponse().flushBuffer();

            context.dispatch("/biggestAsyncRequestTest2");
        } catch (IOException | ServletException e) {
            e.printStackTrace();
        }


    }
}

Второй рабочий поток

public class BiggestAsyncSecondWorkerThread implements Runnable {
    private AsyncContext context;

    public BiggestAsyncSecondWorkerThread(AsyncContext context) {
        this.context = context;
    }
    @Override
    public void run() {
        //The idea is to write something to the response and then dispatch.
        try {
            AsyncRequestProcessor.waitingTime(6000);
            PrintWriter writer = context.getResponse().getWriter();

            context.getRequest().getRequestDispatcher("pages/common/cr_leftnav.jsp").
                    include(context.getRequest(), context.getResponse());
            writer.print("    <div id=\"content-body\">\n" +
                    "            <h3>The external app</h3>");
            writer.print("<p>This is the page you have been waiting so patiently for. After one round of asynchronous processing" +
                    "here you are. I love you..!!</p>");
            writer.print(" </div>\n" +
                    "    </div>\n" +
                    "</div>\n" +
                    "</body>\n" +
                    "</html>");

            context.getResponse().flushBuffer();

           //context.complete();
            context.dispatch();
        } catch (IOException | ServletException e) {
            e.printStackTrace();
        }


    }
}

И, наконец, первоначальный вызов от JSP, который вызвал этот запрос в первую очередь

<div id="sidebar">
    <ul id="parent_nav">
                <li><a href="${pageContext.request.contextPath}/biggestAsyncRequestTest">Checking everything async does</a></li>
    </ul>
</div>

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

Некоторая дополнительная информация

До того, как ошибка, о которой я упоминал в верхней части страницы, печатается, в журналах печатаются следующие строки, свидетельствующие о том, что в строке 23 второго сервлета происходит ошибка.

<<AsyncRequestLoggingFilter>> This is BEFORE calling the doFilter
Hi I'm the servlet BiggestAsyncFirstServlet and my job is done
<<AsyncRequestLoggingFilter>> This is AFTER returning from  the doFilter call
<<AsyncRequestLoggingFilter>> This is BEFORE calling the doFilter during the ASYNC dispatching

Мои извинения за такой длинный вопрос. Любая помощь, которую я могу получить, чтобы понять, почему он говорит: "Фильтр или сервлет текущей цепочки не поддерживает асинхронные операции". Несмотря на то, что все компоненты помечены asyncSupported = true, это очень ценится.

Спасибо, Кингшук

0 ответов

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