问题描述
我遇到有关HttpSession的 @Async
任务的问题.我想以异步方法将数据保存在会话中.发生的情况是正确返回了响应,但是在会话中保存数据时出现错误.请帮忙.
I am facing an issue regarding @Async
task with HttpSession. I want to save the data in session in an async method. What happens is the response is returned correctly but I get an error while saving data in session. Please help.
我的控制器文件:
@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();
}
}
我的Stacktrace:
My Stacktrace:
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中的承诺一样.
因此,通过将服务方法的返回类型从 void
更改为 CompletableFuture< Void>
,可以解决此问题.
On top of my head, If We have @Async
annotations then I think return type should be of type CompletableFuture
like a promise in javascript.
So by changing the return type to service method from void
to CompletableFuture<Void>
solves the problem.
所以我修改了如下代码:
So I modified the code as below:
@Async("threadPoolTaskExecutor")
@Override
public CompletableFuture<Void> myAsyncFunction(String s) {
session.setAttribute("key", s);
return new CompletableFuture<Void>();
}
//要在异步中获取会话对象//这是错误的代码,但请检查适用性
// To get session object in Async// This is bad code but check suitability
所以在这里,我从HttpRequest获取会话对象并将其传递给Service,您在service处添加参数并在控制器上检查这些参数.
不要在服务或控制器上自动连接会话对象.
So here I am getting session object from the HttpRequest and passing it to Service, You add parameters at service and check those parameters at the controller.
Do not autowire session object at service or controller.
@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);
}
}
这篇关于将数据保存到会话时,Spring Async函数异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!