servlet中的多个异步上下文无法正常工作

时间:2018-04-06 23:24:33

标签: asynchronous servlets servlet-3.0

我正在尝试在servlet中练习多个异步请求链,而且我遇到了一种奇怪的行为。不确定它是否与tomcat有关。

所以这是场景。我有一个简单的J2EE maven Web应用程序。

我有两个servlet和一个过滤器。我用asyncSupported = true标记了所有这些标记。当我单击JSP中的链接时,第一个servlet确实接受了请求并使用AsyncContext生成了一个新的工作线程。工作线程然后将某些内容写入响应,提交它(因为我知道它对于servlet中的异步处理是合法的),然后将请求分派给另一个servlet。它一直工作正常。

第二个servlet应该产生第二个工作线程然后计划是使第二个工作线程调用调度(因为我还试图练习无参数调用dispatch())返回到第二个调用它的servlet。但是,在第二个servlet上调用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");
    }

}

第一个Servlet

@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");

    }
}

第二个servlet

@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>

注意:我也有一个异步监听器。但错误似乎与它无关,所以留下它

其他一些信息

在我在顶部打印中提到的错误之前,在日志中打印了以下行,表明它在第二个Servlet的第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

我为这么久的问题道歉。任何帮助我都可以理解它为什么说“当前链的过滤器或servlet不支持异步操作”。尽管所有组件都标有asyncSupported = true,但我们深表赞赏。

谢谢, Kingshuk

0 个答案:

没有答案