原文网址:SpringBoot--解决子线程无法获得HttpServletRequest的attribute的问题_IT利刃出鞘的博客-****博客
简介
本文介绍解决SpringBoot子线程无法获得HttpServletRequest的attribute的问题。
在SpringBoot请求中,如果创建了子线程获取request的attribute,会无法获取到。比如:我想记录日志,将日志放到了request的attribute中:("logContent", "日志内容"),然后创建子线程去获取logContent,然后进行处理。
问题复现
代码
package ;
import ;
import ;
import ;
import ;
import ;
import ;
@RestController
public class HelloController {
@GetMapping("/test")
public String test() {
ServletRequestAttributes servletRequestAttributes =
(ServletRequestAttributes)();
HttpServletRequest request = ();
("logContent", "日志内容:" + ());
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
ServletRequestAttributes servletRequestAttributes =
(ServletRequestAttributes)();
HttpServletRequest request = ();
("子线程运行。获取到的attribute为:"
+ ("logContent"));
}
});
();
return "test success";
}
}
结果(getRequestAttributes返回null)
Exception in thread "Thread-131"
at $(:26)
at (:748)
解决方案
创建子线程之前调用如下代码:
(servletRequestAttributes, true);
代码
package ;
import ;
import ;
import ;
import ;
import ;
import ;
@RestController
public class HelloController {
@GetMapping("/test")
public String test() {
ServletRequestAttributes servletRequestAttributes =
(ServletRequestAttributes)();
HttpServletRequest request = ();
("logContent", "日志内容:" + ());
(servletRequestAttributes, true);
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
ServletRequestAttributes servletRequestAttributes =
(ServletRequestAttributes)();
HttpServletRequest request = ();
("子线程运行。获取到的attribute为:"
+ ("logContent"));
}
});
();
return "test success";
}
}
结果(可以获取到属性)
子线程运行。获取到的attribute为:日志内容:2022-09-03T16:43:18.463
线程安全性
上边的解决方案是否有线程安全问题呢?我在子线程里延时5秒模拟长时间请求,然后多次请求,看结果。如果值都是不一样的话,应该是线程安全的。(本处我无法百分百确定,实际开发中不太建议这么写。实际开发中建议将日志内容作为线程的参数传入,与attribute剥离开)。
代码
package ;
import ;
import ;
import ;
import ;
import ;
import ;
@RestController
public class HelloController {
@GetMapping("/test")
public String test() {
ServletRequestAttributes servletRequestAttributes =
(ServletRequestAttributes)();
HttpServletRequest request = ();
("logContent", "日志内容:" + ());
(servletRequestAttributes, true);
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
ServletRequestAttributes servletRequestAttributes =
(ServletRequestAttributes)();
HttpServletRequest request = ();
("子线程运行。获取到的attribute为:"
+ ("logContent"));
try {
(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
();
return "test success";
}
}
结果(日志内容是新的,应该是线程安全的)
子线程运行。获取到的attribute为:日志内容:2022-09-03T16:46:42.242
子线程运行。获取到的attribute为:日志内容:2022-09-03T16:46:42.799
子线程运行。获取到的attribute为:日志内容:2022-09-03T16:46:43.359
子线程运行。获取到的attribute为:日志内容:2022-09-03T16:46:43.877
子线程运行。获取到的attribute为:日志内容:2022-09-03T16:46:44.392
子线程运行。获取到的attribute为:日志内容:2022-09-03T16:46:44.804
子线程运行。获取到的attribute为:日志内容:2022-09-03T16:46:45.247
子线程运行。获取到的attribute为:日志内容:2022-09-03T16:46:45.610
子线程运行。获取到的attribute为:日志内容:2022-09-03T16:46:46.010
子线程运行。获取到的attribute为:日志内容:2022-09-03T16:46:46.433