我的 ThreadLocal
变量在 HandlerInterceptor
中为每个 request 设置,但有时它在服务层访问时返回 null 而不是预期值。
我假设 ThreadLocal 对象是 thread safe 并且对于单个请求线程是本地的。因此,即使有多个请求正在设置/清除它,它也只会为那个特定的请求线程被清除,而不会影响其他线程。
但是 1-2 次(现在无法重现,即使有很多日志语句)在调试模式下,我遇到服务层中的ThreadLocal
为空(因此得到一个NullPointerException),即使它不应该因为它是在 HandlerInceptor
中设置的,它总是在 spring-boot 的控制器层之前先命中。
下面是ThreadLocal代码真正线程安全的,当多个请求线程同时访问它时。
是否有可能Interceptor在一个Thread中执行并且控制器在另一个线程中执行并且在拦截器设置ThreadLocal中的值之前控制器线程以某种方式首先执行。
代码:
ThreadLocal.class
@Component
public class ThreadLocalUtil {
private static final ThreadLocal<ConstantsConfig> constantsConfig = new ThreadLocal<>();
public static ConstantsConfig getConstantsConfig() {
return constantsConfig.get();
}
public static void setConstantsConfig(ConstantsConfig config) {
constantsConfig.set(config);
}
public static void clearConstantsConfig() {
constantsConfig.remove();
}
}
HandlerInceptor.class
public class RequestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (request.getRequestURI().equals(ControllerEndpoints.HEALTH)) {
return true;
}
// we are always setting ThreadLocal, before accessing it in service layer.
setConstants(request);
logThreadLocal();
return true;
}
private void setConstants(HttpServletRequest request) {
ThreadLocalUtil.setConstantsConfig(BeanUtil.getBean(ImplConstantsConfig.class))
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
if (request.getRequestURI().equals(ControllerEndpoints.HEALTH)) {
return;
}
ThreadLocalUtil.clearConstantsConfig();
}
AccessorService.class
// accessed in multiple service classes for 1 request/response cycle.
ThreadLocalUtil.getConstantsConfig().getProperty1()
ThreadLocalUtil.getConstantsConfig().getProperty2()