当前位置: 首页 > 知识库问答 >
问题:

在Java8中使用HttpServletRequest和ParallelStream

向泽语
2023-03-14

我有一个简单的应用程序,它将公开一个名为'GET AllDeviceData'的RESTFul GETendpoint,它将简单地从DB中的device表返回所有设备的提取数据列表。

对于每个请求,我通过验证HttpServletRequest.getUserPrincipal()方法来验证用户身份。为了加速这个过程,我使用了parallelStream和lambda表达式。

在ParallelStream中,我调用了另一个名为'Get DeviceData'的方法,在该方法中,我正在进行身份验证并从DB中提取数据。

问题是,当并行流进程调用getDeviceDat方法时,我得到一个NullPointer异常,无法完成并行steam。

问题是,HttpServletRequest.getUserPrincipal()在方法中为空。但它实际上存在于'get alldevicedata'(lambda表达式所在的位置)中。

如果我将“parallel stream()'替换为”stream()'(但在本例中不存在并行性质),则这不会产生任何问题。

@Override
@ResponseBody
@RequestMapping(value = "getAllDeviceData", method = RequestMethod.GET, consumes = "*")
public List<List<Data>> getAllDeviceData(    
        @RequestParam(value = "recordLimit", required = false) final Integer recordLimit,         
        final HttpServletRequest request) {

    final List<Device> deviceList = deviceService.getAllDevices();   
    final List<List<Data>> dataList = deviceList.parallelStream().map(device -> getDeviceData(recordLimit, device.getDeviceId(), request)).collect(Collectors.toList());

    return alerts;
}

private List<Data> getDeviceData(@RequestParam(value = "recordLimit", required = false) Integer recordLimit, String deviceId, HttpServletRequest request) {
    if(request.getUserPrincipal() == null){
        logger.info("User Principle Null - 1");
    }else {
        logger.info("User Principle Not Null - 1");
    }
    authService.doAuthenticate(request);

    // if authrnticated proceed with following...
    List<Data> deviceData = deviceService.getGetDeviceData(deviceId);
    return deviceData;
}

但是,我观察到了一些东西。

请看上述应用程序的以下日志(省略了不必要的部分)。

在它中,主线程(例如:http-nio-7070-exec-2等--这是应用程序服务器线程池的主线程)工作良好,因为它打印出“User Principal Not Null-1”,但在并行流的分解线程(如ForkJoinPool.CommonPool-Worker-2等)中,HttpServletRequest.GetUserPrincipal()变为Null。

2018-01-15 15:28:06,897 INFO [http-nio-7070-exec-2] User Principle Not Null - 1 
2018-01-15 15:28:06,897 INFO [ForkJoinPool.commonPool-worker-2] User Principle Null - 1 
2018-01-15 15:28:06,906 INFO [ForkJoinPool.commonPool-worker-3] User Principle Null - 1 

2018-01-15 15:28:06,955 INFO [ForkJoinPool.commonPool-worker-2] User Principle Null - 1 
2018-01-15 15:28:06,955 INFO [ForkJoinPool.commonPool-worker-1] User Principle Null - 1

2018-01-15 15:28:06,957 INFO [ForkJoinPool.commonPool-worker-2] User Principle Null - 1 
2018-01-15 15:28:06,959 INFO [ForkJoinPool.commonPool-worker-3] User Principle Null - 1
2018-01-15 15:28:07,064 INFO [ForkJoinPool.commonPool-worker-2] User Principle Null - 1 

2018-01-15 15:28:07,076 INFO [http-nio-7070-exec-2] User Principle Not Null -1

2018-01-15 15:28:07,078 INFO [ForkJoinPool.commonPool-worker-1] User Principle Null - 1

我对lambda表达式和并行流还是新手。请帮助我理解这里的问题是什么。

Java详细信息:

java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)

共有1个答案

杜联
2023-03-14

根本原因是Spring正在将SecurityContextHolderAwareRequestWrapper实例注入到您的方法中。调用equest.getUserPrincipal()时,此包装将调用以下行:

private Authentication getAuthentication() {
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();

SecurityContextHolder有不同的策略。默认情况下,使用mode_threadlocal策略。这就是为什么在主线程中有用户原则,而在forkjoinpool线程中没有用户原则的原因。

-dspring.security.strategy=mode_inheritablethreadlocalVM选项是解决问题的一种方法。InheritableThreadLocal javadoc和InheritableThreadLocalSecurityContextHolderStrategy源代码可能会为理解带来额外的价值。

 类似资料:
  • 在Oracle“原始数据类型”页面中,它提到Java8增加了对无符号int和long的支持: 那么,有没有办法声明一个无符号的int或long呢?

  • 我使用SimpleDateFormat来格式化或验证日期,但我想通过使用java 8 DateTimeFormatter使其线程安全。我在实现某些要求时遇到了麻烦。 我的应用程序将只接受三种类型的格式。“yyyy-MM-dd”, “yyyy-MM”, “yyyy” 以下是输入和预期输出: > 我如何在java 8 DateTimeForma中实现相同的结果tter? /* java 8日期时间格式

  • 我是新来的swagger和使用它的留档。我目前正在尝试使用swagger来显示PATCH请求的请求体。以前,PATCH方法的参数是正在更新的对象的DTO,这使得显示对象的属性变得非常容易(因为我正在使用SpringBoot,并使用完美地工作)。然而,现在PATCH方法的参数是一个HttpServlet请求。我不想在swagger doc中显示HttpServlet请求(这似乎是自动发生的),而是想

  • 我遇到了一种情况,在处理请求之前,我必须更新它。基本上,我必须用一个可以随时间变化的属性来更新请求。要求消费者随请求一起发送属性是不实际的..所以,我觉得唯一的办法就是..在处理请求之前,更新控制器方法中的请求.. 到目前为止,控制器方法中使用了HttpServletRequest。然后将请求读取为流,然后将其转换为json字符串进行处理。我正在考虑用@RequestBody替换它,并将请求读入p

  • 我正在尝试使用<code>LocalTime解析08:24:55(HH:mm:ss)和8:24:50(H:mm:ss)。java 8中的parse()方法。以下代码成功执行并打印08:24:55: 但同一组代码在输入8:24:55时失败,并抛出错误: 线程“main”java.time.format中出现异常。DateTimeParseException:无法在索引0处分析文本“8:24:55”