简体   繁体   中英

Long polling with JQuery ajax and Spring DeferredResult returns blank result

I am trying to use Spring's DeferredResult to perform long polling. The controller looks like this:

package com.example.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.DeferredResult;

import com.example.controller.interfaces.ExampleControllerInterface;

@Component
public class ExampleController implements ExampleControllerInterface{

    @Override
    public String viewHomePage(HttpServletRequest request, ModelMap model, HttpSession session){
        return "index";
    }

    @ResponseBody
    @RequestMapping(value = "/pollContent", method = RequestMethod.GET)
    public DeferredResult<String> pollContent(HttpServletRequest request, ModelMap model, HttpSession session){

        System.out.println("Polling content.");

        final DeferredResult<String> result = new DeferredResult<>();

        new Thread(){
            public void run(){
        try {
            System.out.println("Sleeping for 10 seconds.");
            Thread.sleep(10000);
        } 
        catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Setting result.");
        result.setResult("testing");

        }
        }.start();

        System.out.println("Returning result.");
        return result;
    }
}

I'm using JQuery's ajax() function to access the async pollContent() controller function:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Spring Example</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
    <script>
    function pollContent() {
        $.ajax({url: "pollContent", success: function(result){
            console.log("Polled result: " + result);
            $("#polledContent").html(result);
        }});
    }
    $(pollContent);
    </script>
  </head>

<body>
    <p>This example uses JQuery's ajax() function to access a Spring controller's async function. After the page loads, it should return in 10 seconds and change the below text:</p>
    <p id="polledContent">Loading...</p>
    <p>Instead, the call returns immediately and the result is blank.</p>
</body>
</html>

I would expect the ajax() call to take 10 seconds to return to its success handler, and then to populate the polledContent p tag with the result.

Instead, the ajax() call returns immediately, and the result is blank. The controller function does proceed to set and return the result, but that result doesn't appear to "go" anywhere on the client side.

I'm using annotation configuration instead of web.xml, and I've enabled async in my config class:

package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@EnableWebMvc 
@EnableAsync
@ComponentScan({"com.example.controller", "com.example.config"})
public class WebConfig extends WebMvcConfigurerAdapter {

    @Bean
    public InternalResourceViewResolver internalResourceViewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/jsp/");
        viewResolver.setSuffix(".jsp");

        return viewResolver;
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
        super.configureDefaultServletHandling(configurer);
    }
}

Edit: As requested, here is the logger output:

TRACE [http-nio-8080-exec-4] (FrameworkServlet.java:1043) - Bound request context to thread: org.apache.catalina.connector.RequestFacade@49da6e5
DEBUG [http-nio-8080-exec-4] (DispatcherServlet.java:838) - DispatcherServlet with name 'dispatcher' processing GET request for [/SpringExample/]
TRACE [http-nio-8080-exec-4] (DispatcherServlet.java:1095) - Testing handler map [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@3da4a56] in DispatcherServlet with name 'dispatcher'
DEBUG [http-nio-8080-exec-4] (AbstractHandlerMethodMapping.java:246) - Looking up handler method for path /
TRACE [http-nio-8080-exec-4] (AbstractHandlerMethodMapping.java:284) - Found 1 matching mapping(s) for [/] : [{[/],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}]
DEBUG [http-nio-8080-exec-4] (AbstractHandlerMethodMapping.java:251) - Returning handler method [public abstract java.lang.String com.example.controller.interfaces.ExampleControllerInterface.viewHomePage(javax.servlet.http.HttpServletRequest,org.springframework.ui.ModelMap,javax.servlet.http.HttpSession)]
DEBUG [http-nio-8080-exec-4] (AbstractBeanFactory.java:249) - Returning cached instance of singleton bean 'exampleController'
TRACE [http-nio-8080-exec-4] (DispatcherServlet.java:1135) - Testing handler adapter [org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter@5fe4ef74]
TRACE [http-nio-8080-exec-4] (DispatcherServlet.java:1135) - Testing handler adapter [org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter@c041485]
TRACE [http-nio-8080-exec-4] (DispatcherServlet.java:1135) - Testing handler adapter [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@24adb017]
DEBUG [http-nio-8080-exec-4] (DispatcherServlet.java:925) - Last-Modified value for [/SpringExample/] is: -1
TRACE [http-nio-8080-exec-4] (InvocableHandlerMethod.java:130) - Invoking [$Proxy20.viewHomePage] method with arguments [org.apache.catalina.connector.RequestFacade@49da6e5, {}, org.apache.catalina.session.StandardSessionFacade@2f88f324]
TRACE [http-nio-8080-exec-4] (InvocableHandlerMethod.java:134) - Method [viewHomePage] returned [index]
TRACE [http-nio-8080-exec-4] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler@5c39d55e] supports [class java.lang.String]
TRACE [http-nio-8080-exec-4] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.method.annotation.ModelMethodProcessor@20c740be] supports [class java.lang.String]
TRACE [http-nio-8080-exec-4] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.ViewMethodReturnValueHandler@7cd737e7] supports [class java.lang.String]
TRACE [http-nio-8080-exec-4] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor@77170f30] supports [class java.lang.String]
TRACE [http-nio-8080-exec-4] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.HttpHeadersReturnValueHandler@6516a7a9] supports [class java.lang.String]
TRACE [http-nio-8080-exec-4] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.CallableMethodReturnValueHandler@25b98d19] supports [class java.lang.String]
TRACE [http-nio-8080-exec-4] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.DeferredResultMethodReturnValueHandler@2cb6fe5a] supports [class java.lang.String]
TRACE [http-nio-8080-exec-4] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.AsyncTaskMethodReturnValueHandler@b7a0149] supports [class java.lang.String]
TRACE [http-nio-8080-exec-4] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.method.annotation.ModelAttributeMethodProcessor@45accbf1] supports [class java.lang.String]
TRACE [http-nio-8080-exec-4] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor@68f7a9ab] supports [class java.lang.String]
TRACE [http-nio-8080-exec-4] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.ViewNameMethodReturnValueHandler@495843fd] supports [class java.lang.String]
DEBUG [http-nio-8080-exec-4] (DispatcherServlet.java:1218) - Rendering view [org.springframework.web.servlet.view.JstlView: name 'index'; URL [/WEB-INF/jsp/index.jsp]] in DispatcherServlet with name 'dispatcher'
TRACE [http-nio-8080-exec-4] (AbstractView.java:261) - Rendering view with name 'index' with model {} and static attributes {}
DEBUG [http-nio-8080-exec-4] (InternalResourceView.java:207) - Forwarding to resource [/WEB-INF/jsp/index.jsp] in InternalResourceView 'index'
TRACE [http-nio-8080-exec-4] (FrameworkServlet.java:1053) - Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@49da6e5
DEBUG [http-nio-8080-exec-4] (FrameworkServlet.java:991) - Successfully completed request
TRACE [http-nio-8080-exec-4] (AbstractApplicationContext.java:331) - Publishing event in Root WebApplicationContext: ServletRequestHandledEvent: url=[/SpringExample/]; client=[0:0:0:0:0:0:0:1]; method=[GET]; servlet=[dispatcher]; session=[DB17A129B0B4A37F85D65A1B973EBF3D]; user=[null]; time=[8ms]; status=[OK]
TRACE [http-nio-8080-exec-5] (FrameworkServlet.java:1043) - Bound request context to thread: org.apache.catalina.connector.RequestFacade@49da6e5
DEBUG [http-nio-8080-exec-5] (DispatcherServlet.java:838) - DispatcherServlet with name 'dispatcher' processing GET request for [/SpringExample/pollContent]
TRACE [http-nio-8080-exec-5] (DispatcherServlet.java:1095) - Testing handler map [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@3da4a56] in DispatcherServlet with name 'dispatcher'
DEBUG [http-nio-8080-exec-5] (AbstractHandlerMethodMapping.java:246) - Looking up handler method for path /pollContent
TRACE [http-nio-8080-exec-5] (AbstractHandlerMethodMapping.java:284) - Found 1 matching mapping(s) for [/pollContent] : [{[//pollContent],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}]
DEBUG [http-nio-8080-exec-5] (AbstractHandlerMethodMapping.java:251) - Returning handler method [public abstract org.springframework.web.context.request.async.DeferredResult<java.lang.String> com.example.controller.interfaces.ExampleControllerInterface.pollContent(javax.servlet.http.HttpServletRequest,org.springframework.ui.ModelMap,javax.servlet.http.HttpSession)]
DEBUG [http-nio-8080-exec-5] (AbstractBeanFactory.java:249) - Returning cached instance of singleton bean 'exampleController'
TRACE [http-nio-8080-exec-5] (DispatcherServlet.java:1135) - Testing handler adapter [org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter@5fe4ef74]
TRACE [http-nio-8080-exec-5] (DispatcherServlet.java:1135) - Testing handler adapter [org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter@c041485]
TRACE [http-nio-8080-exec-5] (DispatcherServlet.java:1135) - Testing handler adapter [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@24adb017]
DEBUG [http-nio-8080-exec-5] (DispatcherServlet.java:925) - Last-Modified value for [/SpringExample/pollContent] is: -1
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.method.annotation.RequestParamMethodArgumentResolver@757b2cca] supports [interface javax.servlet.http.HttpServletRequest]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver@2c353cf8] supports [interface javax.servlet.http.HttpServletRequest]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.PathVariableMethodArgumentResolver@208b37e2] supports [interface javax.servlet.http.HttpServletRequest]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.PathVariableMapMethodArgumentResolver@40d0b02b] supports [interface javax.servlet.http.HttpServletRequest]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMethodArgumentResolver@47d7bd17] supports [interface javax.servlet.http.HttpServletRequest]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMapMethodArgumentResolver@4421f1b1] supports [interface javax.servlet.http.HttpServletRequest]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor@17a83b8d] supports [interface javax.servlet.http.HttpServletRequest]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor@6ff67550] supports [interface javax.servlet.http.HttpServletRequest]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver@36ac04ff] supports [interface javax.servlet.http.HttpServletRequest]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver@b23433c] supports [interface javax.servlet.http.HttpServletRequest]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.method.annotation.RequestHeaderMapMethodArgumentResolver@b325664] supports [interface javax.servlet.http.HttpServletRequest]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.ServletCookieValueMethodArgumentResolver@72dcde94] supports [interface javax.servlet.http.HttpServletRequest]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver@426c7ec5] supports [interface javax.servlet.http.HttpServletRequest]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver@5c68f351] supports [interface javax.servlet.http.HttpServletRequest]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.method.annotation.RequestParamMethodArgumentResolver@757b2cca] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver@2c353cf8] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.PathVariableMethodArgumentResolver@208b37e2] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.PathVariableMapMethodArgumentResolver@40d0b02b] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMethodArgumentResolver@47d7bd17] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMapMethodArgumentResolver@4421f1b1] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor@17a83b8d] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor@6ff67550] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver@36ac04ff] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver@b23433c] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.method.annotation.RequestHeaderMapMethodArgumentResolver@b325664] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.ServletCookieValueMethodArgumentResolver@72dcde94] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver@426c7ec5] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver@5c68f351] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.ServletResponseMethodArgumentResolver@69f4b041] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor@5d9983f8] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.RedirectAttributesMethodArgumentResolver@423d0dc5] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.method.annotation.ModelMethodProcessor@e87db7b] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.method.annotation.MapMethodProcessor@1f101f10] supports [class org.springframework.ui.ModelMap]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.method.annotation.RequestParamMethodArgumentResolver@757b2cca] supports [interface javax.servlet.http.HttpSession]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver@2c353cf8] supports [interface javax.servlet.http.HttpSession]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.PathVariableMethodArgumentResolver@208b37e2] supports [interface javax.servlet.http.HttpSession]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.PathVariableMapMethodArgumentResolver@40d0b02b] supports [interface javax.servlet.http.HttpSession]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMethodArgumentResolver@47d7bd17] supports [interface javax.servlet.http.HttpSession]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMapMethodArgumentResolver@4421f1b1] supports [interface javax.servlet.http.HttpSession]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor@17a83b8d] supports [interface javax.servlet.http.HttpSession]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor@6ff67550] supports [interface javax.servlet.http.HttpSession]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver@36ac04ff] supports [interface javax.servlet.http.HttpSession]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver@b23433c] supports [interface javax.servlet.http.HttpSession]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.method.annotation.RequestHeaderMapMethodArgumentResolver@b325664] supports [interface javax.servlet.http.HttpSession]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.ServletCookieValueMethodArgumentResolver@72dcde94] supports [interface javax.servlet.http.HttpSession]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver@426c7ec5] supports [interface javax.servlet.http.HttpSession]
TRACE [http-nio-8080-exec-5] (HandlerMethodArgumentResolverComposite.java:90) - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver@5c68f351] supports [interface javax.servlet.http.HttpSession]
TRACE [http-nio-8080-exec-5] (InvocableHandlerMethod.java:130) - Invoking [$Proxy20.pollContent] method with arguments [org.apache.catalina.connector.RequestFacade@49da6e5, {}, org.apache.catalina.session.StandardSessionFacade@2f88f324]
TRACE [http-nio-8080-exec-5] (InvocableHandlerMethod.java:134) - Method [pollContent] returned [null]
TRACE [http-nio-8080-exec-5] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler@5c39d55e] supports [org.springframework.web.context.request.async.DeferredResult<java.lang.String>]
TRACE [http-nio-8080-exec-5] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.method.annotation.ModelMethodProcessor@20c740be] supports [org.springframework.web.context.request.async.DeferredResult<java.lang.String>]
TRACE [http-nio-8080-exec-5] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.ViewMethodReturnValueHandler@7cd737e7] supports [org.springframework.web.context.request.async.DeferredResult<java.lang.String>]
TRACE [http-nio-8080-exec-5] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor@77170f30] supports [org.springframework.web.context.request.async.DeferredResult<java.lang.String>]
TRACE [http-nio-8080-exec-5] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.HttpHeadersReturnValueHandler@6516a7a9] supports [org.springframework.web.context.request.async.DeferredResult<java.lang.String>]
TRACE [http-nio-8080-exec-5] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.CallableMethodReturnValueHandler@25b98d19] supports [org.springframework.web.context.request.async.DeferredResult<java.lang.String>]
TRACE [http-nio-8080-exec-5] (HandlerMethodReturnValueHandlerComposite.java:80) - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.DeferredResultMethodReturnValueHandler@2cb6fe5a] supports [org.springframework.web.context.request.async.DeferredResult<java.lang.String>]
DEBUG [http-nio-8080-exec-5] (DispatcherServlet.java:1012) - Null ModelAndView returned to DispatcherServlet with name 'dispatcher': assuming HandlerAdapter completed request handling
TRACE [http-nio-8080-exec-5] (FrameworkServlet.java:1053) - Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@49da6e5
DEBUG [http-nio-8080-exec-5] (FrameworkServlet.java:991) - Successfully completed request
TRACE [http-nio-8080-exec-5] (AbstractApplicationContext.java:331) - Publishing event in Root WebApplicationContext: ServletRequestHandledEvent: url=[/SpringExample/pollContent]; client=[0:0:0:0:0:0:0:1]; method=[GET]; servlet=[dispatcher]; session=[DB17A129B0B4A37F85D65A1B973EBF3D]; user=[null]; time=[19ms]; status=[OK]
Polling content.
Returning result.
Sleeping for 10 seconds.
Setting result.

I've created a maven project on GitHub if you want to run this yourself, available here: https://github.com/KevinWorkman/SpringExample

I might just be misunderstanding how long polling is performed using Spring and ajax, or I might be missing something that's required. My questions are:

  • Why doesn't the async controller function return the proper result to the client?
  • What do I have to change to make long polling work?

You've mixed two concepts: @Async method calls and asynchronous request processing within Spring MVC's stack. Although both involve the term asynchronous , they have different goals (or rather are part of different feature sets).

@Async allows for a method's code to be invoked on a separate thread. Spring achieves this by proxying your object and delegating the actual invocation the the real object on another thread. Given

@Component
class Real {
    @Async
    public void method() {}
}

and

Real proxy = ... // get Real from ApplicationContext
proxy.method(); // returns immediately
// continue in this thread

The proxy looks something like

class RealProxy extends Real {
    private ExecutorService executorService; // potentiall configured in Async configuration
    private Real target; // the actual object
    @Override
    public void method() {
        executorService.submit(() -> target.method());
    }
}

This is simple enough to understand with void methods. With non-void method, however, we need a convention. As the documentation linked above states

Even methods that return a value can be invoked asynchronously. However, such methods are required to have a Future typed return value.

Your method has a return type of DeferredResult , which is not a Future . Spring, in this case, doesn't complain, but simply returns null after dispatching the invocation to another thread.

This is where Spring MVC comes in to play. Spring uses a list of HandlerMethodReturnValueHandler objects to handle return values from @RequestMapping annotated handler methods. For DeferredResult , that is DeferredResultMethodReturnValueHandler . If it receives null as a return value, it assumes the request was handled and nothing further needs to be done (this is a common convention among HandlerMethodReturnValueHandler s).

DeferredResult is analogous to Java 8's CompletableFuture type. It's a promise for a result. By returning a value of type DeferredResult , you're promising Spring MVC that you'll have a value at some point (hopefully before it times out). In the meantime, you've dispatched the actual handling to another thread (which will set the value) and the MVC stack can reclaim the request handling thread and have it serve other requests.

To summarize, don't use both of these techniques. Get rid of the @Async and un-comment the new Thread code you have (though you can use a dedicated thread pool). Spring MVC will receive this DeferredResult , it will assume you'll make good on your promise, stash it for later. When you eventually setResult , this will notify Spring to unstash and complete the request processing.


Looking at your github project, you'll need to enable async support

springDispatcher.setAsyncSupported(true);

You also don't need to load a ContextLoaderListener . Get rid of that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM