Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 控制器中并行流中没有线程绑定请求错误_Java_Spring_Spring Boot - Fatal编程技术网

Java 控制器中并行流中没有线程绑定请求错误

Java 控制器中并行流中没有线程绑定请求错误,java,spring,spring-boot,Java,Spring,Spring Boot,我的控制器上有一个端点,它接受ID列表。对于每个ID,我从一个REST端点获取详细信息,我希望异步执行该操作。这是我的实现: @PostMapping("/leaderboard") @ApiOperation("Get clients leaderboard statistics") public List<Dto> clientLeaderboard(@RequestBody List<String> accountIds) { IntStream.rang

我的控制器上有一个端点,它接受ID列表。对于每个ID,我从一个REST端点获取详细信息,我希望异步执行该操作。这是我的实现:

@PostMapping("/leaderboard")
@ApiOperation("Get clients leaderboard statistics")
public List<Dto> clientLeaderboard(@RequestBody List<String> accountIds) {

    IntStream.range(0, accountIds.size()).parallel().forEach(i -> {
        AccountDTO accountDTO = accountMaintenanceRestClient.getAccount(accountIds.get(i));
        // More logic
    }

}

我想澄清一下这个问题

FeignssTokenRequestInterceptor是您的自定义RequestInterceptor,您正试图在apply方法中访问ServletRequest,这从堆栈跟踪中可以明显看出

RequestObjectFactory.getObject(WebApplicationContextUtils.java:320)

此RequestObjectFactory是一个静态内部类,它允许您访问当前请求

private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {
    private RequestObjectFactory() {
    }

    public ServletRequest getObject() {
        return WebApplicationContextUtils.currentRequestAttributes().getRequest();
    }

    public String toString() {
        return "Current HttpServletRequest";
    }
}
如果您没有任何代码访问当前请求,并且它是从OpenFeign类文件调用的,那么唯一的方法是使用顺序流而不是并行流。这很简单

accountIds.stream().forEach(accountId -> {
    AccountDTO accountDTO = accountMaintenanceRestClient.getAccount(accountId);
    // More logic
}

我想澄清一下这个问题

FeignssTokenRequestInterceptor是您的自定义RequestInterceptor,您正试图在apply方法中访问ServletRequest,这从堆栈跟踪中可以明显看出

RequestObjectFactory.getObject(WebApplicationContextUtils.java:320)

此RequestObjectFactory是一个静态内部类,它允许您访问当前请求

private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {
    private RequestObjectFactory() {
    }

    public ServletRequest getObject() {
        return WebApplicationContextUtils.currentRequestAttributes().getRequest();
    }

    public String toString() {
        return "Current HttpServletRequest";
    }
}
如果您没有任何代码访问当前请求,并且它是从OpenFeign类文件调用的,那么唯一的方法是使用顺序流而不是并行流。这很简单

accountIds.stream().forEach(accountId -> {
    AccountDTO accountDTO = accountMaintenanceRestClient.getAccount(accountId);
    // More logic
}

您的
feignssotkenrequestinterceptor
依赖于
HttpServletRequest
代理bean

请求是通过threadlocal公开的,因此threadpool中的线程不知道/不知道它,因此当它尝试从threadlocal映射读取请求时会发生异常

因此,问题基本上缩小到如何将请求设置为线程池的线程上下文

设置一个线程池,如引用的帖子,然后提交任务

@Autowired
ThreadPoolTaskExecutor poolExecutor;

CountdownLatch counter = new CountdownLatch(accountIds.size());
IntStream.range(0, accountIds.size()) // Note that .parallel is omitted
         .forEach(() -> poolExecutor.submit(() -> {
             try {
                your task
             } finally {
                counter.countDown();
             }
         })) 
counter.await(); // Wait for all tasks complete

这是首选的方式,因为默认的并行流用于公共共享池,所以您不应该将一个任务放置在一个具有类似IO的API访问权限的池中)

您的
FeignssTokenRequestInterceptor
依赖于
HttpServletRequest
代理bean

请求是通过threadlocal公开的,因此threadpool中的线程不知道/不知道它,因此当它尝试从threadlocal映射读取请求时会发生异常

因此,问题基本上缩小到如何将请求设置为线程池的线程上下文

设置一个线程池,如引用的帖子,然后提交任务

@Autowired
ThreadPoolTaskExecutor poolExecutor;

CountdownLatch counter = new CountdownLatch(accountIds.size());
IntStream.range(0, accountIds.size()) // Note that .parallel is omitted
         .forEach(() -> poolExecutor.submit(() -> {
             try {
                your task
             } finally {
                counter.countDown();
             }
         })) 
counter.await(); // Wait for all tasks complete

这是首选方式,因为默认并行流用于公共共享池,你不应该把一个任务放在一个像API一样有大量IO访问权限的地方)

我认为这个bean
accountMaintenanceRestClient
必须是
request
session
Scoped共享accountMaintenanceRestClient的代码以及你是如何使用的。@Deadpool是的,看起来它是在线程绑定请求上被处理/调用/自动连接的一个
顶级组件
,不应该处理。添加了剩余的客户端代码。@Nanor你能发布
整个堆栈跟踪
错误吗?我想这个bean
accountMaintenanceRestClient
必须是
请求
会话
范围共享accountMaintenanceRestClient的代码以及您是如何使用的。@Deadpool是的,看起来它正在处理/调用/自动连接一个
顶级组件,该组件在线程绑定请求中不应处理。添加了rest客户端代码。@Nanor您能发布
整个堆栈跟踪
错误吗?
accountIds.stream().forEach(accountId -> {
    AccountDTO accountDTO = accountMaintenanceRestClient.getAccount(accountId);
    // More logic
}
@Autowired
ThreadPoolTaskExecutor poolExecutor;

CountdownLatch counter = new CountdownLatch(accountIds.size());
IntStream.range(0, accountIds.size()) // Note that .parallel is omitted
         .forEach(() -> poolExecutor.submit(() -> {
             try {
                your task
             } finally {
                counter.countDown();
             }
         })) 
counter.await(); // Wait for all tasks complete