我正在使用Spring MVC控制器,并希望在新线程中开始执行任务。但是线程不应该立即启动,而是仅在响应发送到客户端之后。
手段 - 按严格的时间顺序:
我如何实现这一目标?
我想使用spring的异步抽象,调用一个用@Async注释的方法,但这样我就不能保证新线程等待响应被发送。
答案 0 :(得分:11)
您可以使用拦截器。在Spring MVC中处理请求的顺序是:
以上内容已经过度简化,目的只是为了显示拦截器afterCompletion方法在响应发送给客户端之后被调用,具有以下签名:
void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex)
throws Exception
在该方法中,您可以在开始处理之前测试异常的发生和响应的正确性(ex == null && response.getStatus == HttpServletResponse.SC_OK
)。
答案 1 :(得分:5)
如果您的“发送回复后”要求通过“在呈现视图后”完成,则您可以使用HandlerInterceptor的实现。举个例子比较Spring 3 MVC Interceptor tutorial with example,在afterCompletion
触发您的工作。
如果你的工作需要在“电线接通”之后触发,我想知道原因。
答案 2 :(得分:1)
HandlerInterceptor
是解决方案,但代码比预期的要复杂一点。
这里提供了一个代码建议,通过将整个解决方案放在一个类中来简化它:
@RequestMapping("/mypath")
public Object execute() throws Exception {
Object obj = new Object();
result.set(obj); // Save the object to be used after response
return obj;
}
private static final ThreadLocal<Object> result = new ThreadLocal<Object>();
@Bean
public MappedInterceptor interceptor() {
return new MappedInterceptor(Arrays.array("/mypath"), new HandlerInterceptor() {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// Get the saved object
Object results = result.get();
// Clean for the next request
result.set(null);
// TODO Your code to be executed after response.
}
});
}
答案 3 :(得分:0)
您可以在创建响应实体之前将任务添加到阻止队列。让任务执行器定期(每隔x秒)运行一次队列并轮询任务。如果找到任务,则会执行该任务。如果没有,则线程完成其run方法并等待下一次运行(在x秒内)。
如何定期运行任务: http://www.mkyong.com/java/how-to-run-a-task-periodically-in-java/
在控制器和任务执行程序服务中将队列作为依赖项注入。这应该是一个简单的解决方案。
在这个szenario中,您无法确定客户端是否收到请求。但是如果你想要安全(r),请在任务对象中添加一个足够的偏移量(例如当前时间+30秒)。让任务执行者检查轮询任务的截止日期是现在还是过去。否则忽略此次运行的任务。