java - 将数据保存到 Session 时出现 Spring Async 函数异常
问题描述
我面临一个关于@Async
HttpSession 任务的问题。我想以异步方法将数据保存在会话中。发生的情况是响应正确返回,但在会话中保存数据时出现错误。请帮忙。
我的控制器文件:
@RequestScope
@Controller
public class SomeController {
@Autowired
private ISomeService iSomeService;
@ResponseBody
@GetMapping("/some-func")
public String someFunc() {
iSomeService.myAsyncFunction("hello");
return "ok";
}
}
我的服务文件:
@RequestScope
@Service
public class SomeServiceImpl implements ISomeService {
@Autowired
private HttpSession session;
@Async("threadPoolTaskExecutor")
@Override
public void myAsyncFunction(String s) {
session.setAttribute("key", s);
}
}
我的配置文件:
@EnableAsync
@Configuration
public class ThreadConfig {
@Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
return new ThreadPoolTaskExecutor();
}
}
我的堆栈跟踪:
2019-03-07 17:23:16.065 ERROR 29179 --- [lTaskExecutor-1] .a.i.SimpleAsyncUncaughtExceptionHandler : Unexpected error occurred invoking async method: public void com.example.demo.SomeServiceImpl.myAsyncFunction(java.lang.String)
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at org.springframework.web.context.support.WebApplicationContextUtils.currentRequestAttributes(WebApplicationContextUtils.java:309) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at org.springframework.web.context.support.WebApplicationContextUtils.access$400(WebApplicationContextUtils.java:64) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at org.springframework.web.context.support.WebApplicationContextUtils$SessionObjectFactory.getObject(WebApplicationContextUtils.java:366) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at org.springframework.web.context.support.WebApplicationContextUtils$SessionObjectFactory.getObject(WebApplicationContextUtils.java:361) ~[spring-web-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler.invoke(AutowireUtils.java:307) ~[spring-beans-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at com.sun.proxy.$Proxy93.setAttribute(Unknown Source) ~[na:na]
at com.example.demo.SomeServiceImpl.myAsyncFunction(SomeServiceImpl.java:21) ~[classes/:na]
at com.example.demo.SomeServiceImpl$$FastClassBySpringCGLIB$$9dbf1607.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:736) ~[spring-aop-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:115) ~[spring-aop-4.3.22.RELEASE.jar:4.3.22.RELEASE]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_191]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_191]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_191]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_191]
解决方案
在我的脑海中,如果我们有@Async
注释,那么我认为返回类型应该是CompletableFuture
类似于 javascript 中的承诺的类型。
因此,通过将返回类型更改为服务方法 fromvoid
来CompletableFuture<Void>
解决问题。
所以我修改了代码如下:
@Async("threadPoolTaskExecutor")
@Override
public CompletableFuture<Void> myAsyncFunction(String s) {
session.setAttribute("key", s);
return new CompletableFuture<Void>();
}
// 在异步中获取会话对象 // 这是错误的代码,但请检查适用性
所以在这里我从 HttpRequest 获取会话对象并将其传递给服务,您在服务中添加参数并在控制器中检查这些参数。
不要在服务或控制器上自动装配会话对象。
@RequestScope
@Controller
public class SomeController {
@Autowired
private SomeServiceImpl iSomeService;
@ResponseBody
@GetMapping("/some-func")
public String someFunc(HttpServletRequest request) throws ExecutionException, InterruptedException {
HttpSession session = request.getSession();
CompletableFuture<HttpSession> completableFuture= iSomeService.myAsyncFunction(session, "hello");
HttpSession session1=completableFuture.get();
System.out.println(session1.getAttribute("key"));
return "ok";
}
}
@RequestScope
@Service
public class SomeServiceImpl {
@Async("threadPoolTaskExecutor")
public CompletableFuture<HttpSession> myAsyncFunction(HttpSession session, String s) {
session.setAttribute("key", s);
return CompletableFuture.completedFuture(session);
}
}
推荐阅读
- azure - Azure DevOps 构建 YML 不是条件不工作
- node.js - Macbook m1节点js docker镜像构建失败
- ruby-on-rails - 使用 ActiveRecord 锁定回调内的关联?
- javascript - 在 JS 中编辑 JSON 并将其放入数组中
- filter - 过滤不带双引号的ansible输出参数
- python - 如果 python 日志处理程序引发异常会发生什么?
- forms - 如何直接从图表生成谷歌表单(或类似的东西)?
- django - 如何用pythonanywhere配置django项目的sqlite
- node.js - Node.js 包发布到 github,^ 类型依赖没有解决
- reactjs - 切换反应组件不会呈现 css