Spring Async function exception while saving data

2019-08-18 16:31发布

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.

My controller file:

@RequestScope
@Controller
public class SomeController {

    @Autowired
    private ISomeService iSomeService;

    @ResponseBody
    @GetMapping("/some-func")
    public String someFunc() {
        iSomeService.myAsyncFunction("hello");
        return "ok";
    }
}

My Service file:

@RequestScope
@Service
public class SomeServiceImpl implements ISomeService {

    @Autowired
    private HttpSession session;

    @Async("threadPoolTaskExecutor")
    @Override
    public void myAsyncFunction(String s) {

        session.setAttribute("key", s);
    }
}

My configuration file:

@EnableAsync
@Configuration
public class ThreadConfig {

    @Bean(name = "threadPoolTaskExecutor")
    public Executor threadPoolTaskExecutor() {
        return new ThreadPoolTaskExecutor();
    }
}

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]

2条回答
Juvenile、少年°
2楼-- · 2019-08-18 16:47

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

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);
}
}
查看更多
ゆ 、 Hurt°
3楼-- · 2019-08-18 17:00

According to Async java doc. void is a legal return type.

In terms of target method signatures, any parameter types are supported. However, the return type is constrained to either {@code void} or {@link java.util.concurrent.Future}. In the latter case, you may declare the more specific {@link org.springframework.util.concurrent.ListenableFuture} or {@link java.util.concurrent.CompletableFuture} types which allow for richer interaction with the asynchronous task and for immediate composition with further processing steps.

I think this link may help you.

查看更多
登录 后发表回答