使用最新最好的Spring 3.2.3,Tomcat 7.0.42,Servlet 3.0容器,Java 7.我们需要为我们的响应做JSONP,所以我们通过像这样做一个Servlet过滤器实现它:
但目前没有web.xml。我们正在使用Java Annotation Config。
在我们的@Controller
中,我们将返回DeferredResult<String>
,然后在我们@Service
调用的@Controller
中,我们有@Async
注解。我们进入@Async
路由(而不是AysncContext路由)的原因是因为这是一种“即发即弃”类型的异步操作。但我确实需要向请求者返回一些说明操作已经开始的JSON。
@RequestMapping(method = RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public DeferredResult<String> testing(@RequestParam(value="submit", required=true) String param)
{
final DeferredResult<String> result = new DeferredResult<String>();
service.doIt(param, result);
return result;
}
在我们的@Service
@Async
public DeferredResult<String> doIt(String param2, DeferredResult<String> result)
{
log.info("Calling Async doIt Method");
result.setResult("{hello:there}");
}
我被卡住了......我正在试图弄清楚是否有一种方法可以为Java Config中的Servlet过滤器添加 async-supported 标记?我的基础是看到这个演示文稿(幻灯片28):
http://rstoyanchev.github.io/spring-mvc-32-update/#28
其他一些信息:
在配置上有@EnableAsync
,我们正在使用AbstractAnnotationConfigDispatcherServletInitializer来定义我们的应用程序,但我似乎无法弄清楚如何判断使用异步过滤器(仅使用{{1}返回我们的JsonpFilter)。
基本上发生的事情是JSONP过滤器没有“包装”......但我确实看到过滤器第二次调用,在TaskExecutor线程中设置了结果后..但此时响应已经已经消失了...所以,我看到过滤器“获取数据”两次..在getServletFilters()
方法退出时正确,然后在设置DeferredResult.setResult()之后第二次。
我们也在Filter类上尝试了这个:
@Controller
但是这样做不起作用(甚至看起来甚至根据日志制作了2个单独的过滤器..但是,我可能在那里做错了。)
如果我们需要,我们可以切换到Callable。这不是什么大问题。我确实看到了DeferredResult和Callable之间在Spring知道的线程方面存在一些差异。
如果答案是您需要使用web.xml,那么使用web.xml混合执行Java Config的任何非常好的方法都可用吗?
编辑1:
基于阅读一些不同的资源,我发现了一些事情:
Servlet过滤器
所有Spring Framework Servlet过滤器实现都已根据需要进行了修改,以便在异步请求处理中工作。如 对于任何其他过滤器,一些将工作 - 通常是那些 预处理,以及其他需要修改 - 通常是那些 在请求结束时进行后处理。这样的过滤器会 需要识别初始Servlet容器线程的时间 退出,让另一个线程继续处理,以及何时 它们作为要完成的异步调度的一部分被调用 处理 *
使用DeferredResult进行异步请求处理的事件序列在原理上是相同的,除非它取决于 应用程序从某个线程产生异步结果:(1) Controller返回DeferredResult并将其保存在内存中 队列或列表,可以访问它,(2)Spring MVC启动异步 处理,(3)DispatcherServlet和所有已配置的Filter的退出 请求处理线程,但响应保持打开,(4) 应用程序从某些线程和Spring MVC设置theDeferredResult 将请求调度回Servlet容器,(5) 再次调用DispatcherServlet并继续处理 异步生成结果。
所以,基本上,我知道/知道单独的线程会调用过滤器...这不是什么让我感到高兴..这是如何判断过滤器是否应该修改响应...和你无法查看数据的大小,因为0字节可能是正确的“答案”。
所以,我现在只写DispatchType = ASYNC
不确定长期做这是否正确..但是,似乎确实解决了这个问题。
还有其他建议/想法吗?
答案 0 :(得分:2)
如果您正在扩展AbstractAnnotationConfigDispatcherServletInitializer,您可以覆盖此方法并设置异步支持:
@Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setInitParameter("dispatchOptionsRequest", "true");
registration.setAsyncSupported(true);
}
答案 1 :(得分:2)
我通过将@Async添加到控制器方法来解决这个问题。我的猜测是,这样做可以处理幕后的过滤器。
答案 2 :(得分:1)
您只需要在每个servlet实例上设置asyncSupport标志,如下所示:
@Override
public void onStartup(final ServletContext servletContext)
throws ServletException {
final AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
root.setServletContext(servletContext);
root.scan("com.my.site");
root.refresh();
final Dynamic servlet = servletContext.addServlet("cf-validator",
new DispatcherServlet(root));
servlet.setLoadOnStartup(1);
servlet.addMapping("/api/*");
servlet.setAsyncSupported(true);
}
答案 3 :(得分:1)
您可以在web.xml文件的servlet定义中将async-supported
设置为true
:
<servlet>
<servlet-name>my-servlet</servlet-name>
<async-supported>true</async-supported>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>