我有一个简单的应用程序,它将公开一个名为'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)
根本原因是Spring正在将SecurityContextHolderAwareRequestWrapper实例注入到您的方法中。调用equest.getUserPrincipal()
时,此包装将调用以下行:
private Authentication getAuthentication() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
SecurityContextHolder有不同的策略。默认情况下,使用mode_threadlocal
策略。这就是为什么在主线程中有用户原则,而在forkjoinpool线程中没有用户原则的原因。
-dspring.security.strategy=mode_inheritablethreadlocal
VM选项是解决问题的一种方法。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”