Java SpringAsync,如何在异步任务执行器中启用请求范围

Java SpringAsync,如何在异步任务执行器中启用请求范围,java,spring,multithreading,spring-boot,asynchronous,Java,Spring,Multithreading,Spring Boot,Asynchronous,我尝试使用@Asyncde-spring,在我的服务中,我使用了一个范围为会话的bean,我总是遇到以下错误: org.springframework.beans.factory.BeanCreationException:错误 正在创建名为“scopedTarget.classSession”的bean: 当前线程的作用域“会话”未处于活动状态;考虑 如果要引用此bean,请为此bean定义作用域代理 从独生子女;嵌套异常为java.lang.IllegalStateException: 未找

我尝试使用
@Async
de-spring,在我的服务中,我使用了一个范围为
会话
的bean,我总是遇到以下错误:

org.springframework.beans.factory.BeanCreationException:错误 正在创建名为“scopedTarget.classSession”的bean: 当前线程的作用域“会话”未处于活动状态;考虑 如果要引用此bean,请为此bean定义作用域代理 从独生子女;嵌套异常为java.lang.IllegalStateException: 未找到会话且请求已完成-无法创建新会话 会话

如上所述,未找到会话,请求已完成。我实现了AsyncConfigurer以覆盖ThreadPoolTaskExecutor:下面是我的代码

控制器:

@Autowired 
MyService myService;

@RequestMapping(value = "/doIt", method = RequestMethod.PUT)
public HttpEntity initiateCurrent(..){

myService.do();
...
}
我的服务

@Autowired 
ClassWithScopeSession classSession;

@Async("taskExecutor")
public void do(){
....
...
classSession.doService();
}
//线程池任务执行器上方

public class ContextAwareCallable<T> implements Callable<T> {
    private Callable<T> task;
    private RequestAttributes context;

    @Autowired
    private ApplicationContext appContext;

    public ContextAwareCallable(Callable<T> task, RequestAttributes context) {
        this.task = task;
        this.context = context;
    }

    @Override
    public T call() throws Exception {
        if (context != null) {
            RequestContextHolder.setRequestAttributes(context);
        }
        try {
            return task.call();
        } finally {
            RequestContextHolder.resetRequestAttributes();
        }
    }
}

public class ContextAwarePoolExecutor extends ThreadPoolTaskExecutor {
    @Override
    public <T> Future<T> submit(Callable<T> task) {
        return super.submit(new ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()));
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        return super.submitListenable(new ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()));
    }
}

@Configuration
@EnableAsync
public class ExecutorConfig  implements AsyncConfigurer {

    @Override
    @Bean(name="taskExecutor")
    public Executor getAsyncExecutor() {
        return new ContextAwarePoolExecutor();
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return null;
    }
}
public类ContextAwareCallable实现可调用{
私有可调用任务;
私有属性上下文;
@自动连线
私有应用上下文appContext;
公共上下文可调用(可调用任务、RequestAttributes上下文){
this.task=任务;
this.context=上下文;
}
@凌驾
public T call()引发异常{
if(上下文!=null){
setRequestAttributes(上下文);
}
试一试{
返回task.call();
}最后{
resetRequestAttributes();
}
}
}
公共类ContextAwarePoolExecutor扩展ThreadPoolTaskExecutor{
@凌驾
公共未来提交(可调用任务){
返回super.submit(新的ContextAwareCallable(任务,RequestContextHolder.currentRequestAttributes());
}
@凌驾
public ListenableFuture submitListenable(可调用任务){
返回super.submitListenable(新的ContextAwareCallable(任务,RequestContextHolder.currentRequestAttributes());
}
}
@配置
@使能同步
公共类ExecutorConfig实现AsyncConfigurer{
@凌驾
@Bean(name=“taskExecutor”)
公共执行器getAsyncExecutor(){
返回新的ContextAwarePoolExecutor();
}
@凌驾
公共AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler(){
返回null;
}
}

我遵循了这个

您需要替代execute方法:

@Override
public void execute(Runnable task) {
    super.execute(new ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()));
}
并将您的ContextAwareCallable更新为:

public class ContextAwareCallable implements Runnable {

    private Runnable task;
    private RequestAttributes context;

    public ContextAwareCallable(Runnable task, RequestAttributes context) {
        this.task = task;
        this.context = context;
    }

    @Override
    public void run() {
        if (context != null) {
            RequestContextHolder.setRequestAttributes(context);
        }

        task.run();
    }
}
我不是大师,但这个解决方案对我很有效

使用
@Async
注释方法后,它将在
ThreadPoolTaskExecutor
类上运行
execute()
方法,而不是
submit()
submitListenable()

在我的解决方案中,它返回
CompletableFuture
。这很奇怪,因为execute不返回任何内容


希望它能帮助别人。

我有一个多租户应用程序,使用异步方法。有人返回一个完整的未来。 如前所述,现在它对我有效

@Configuration
@使能同步 公共类仪表板AsyncExecutorConfig{

@Bean("MyTaskExecutor")
public TaskExecutor taskExecutor() {
    ThreadPoolTaskExecutor executor = new ContextAwarePoolExecutor();
    executor.setCorePoolSize(5);
    executor.setMaxPoolSize(5);
    executor.setQueueCapacity(500);
    executor.setAllowCoreThreadTimeOut(true);
    executor.setThreadNamePrefix("thread");
    executor.initialize();
    return executor;
}
}

公共类ContextAwarePoolExecutor扩展ThreadPoolTaskExecutor{

   @Override
   public <T> Future<T> submit(Callable<T> task) {
      return super.submit(new ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()));
   }

   @Override
   public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
     return super.submitListenable(new ContextAwareCallable(task, 
     RequestContextHolder.currentRequestAttributes()));

   }
   
   //FOR COMPLETABLE FUTURE
   @Override
   public void execute(Runnable task) {
       super.execute(new ContextAwareCallableRunnable(task, RequestContextHolder.currentRequestAttributes()));
   }       
@覆盖
公共未来提交(可调用任务){
返回super.submit(新的ContextAwareCallable(任务,RequestContextHolder.currentRequestAttributes());
}
@凌驾
public ListenableFuture submitListenable(可调用任务){
返回super.submitListenable(新上下文可调用)(任务,
RequestContextHolder.currentRequestAttributes());
}
//为了完全的未来
@凌驾
公共void执行(可运行任务){
execute(新的ContextawarCallableRunnable(任务,RequestContextHolder.currentRequestAttributes());
}       
}

public类contextawarcalablerunnable实现Runnable{
私有可运行任务;
私有属性上下文;
public contextawarcalablerunnable(Runnable任务、RequestAttributes上下文){
this.task=任务;
this.context=上下文;
}
@凌驾
公开募捐{
if(上下文!=null){
setRequestAttributes(上下文);
}
task.run();
}

}

不确定它是否有帮助,但不要自动连接
classSession
,而是尝试将
classSession
作为参数传递给
do()
@AndrewS谢谢您的建议,但这是不可能的。。。
public class ContextAwareCallableRunnable<T> implements Runnable {
private Runnable task;
private RequestAttributes context;

public ContextAwareCallableRunnable(Runnable task, RequestAttributes context) {
    this.task = task;
    this.context = context;
}

@Override
public void run() {
    if (context != null) {
        RequestContextHolder.setRequestAttributes(context);
    }
    task.run();
}