关于java并发场景下,HttpServletRequst中session丢失问题

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

关于java并发场景下,HttpServletRequst中session丢失问题

FlyingBread   2021-01-25 我要评论

使用场景:

  在list数据进来之后使用安全数组    Lists.newCopyOnWriteArrayList()

进行了   parallelStream  并行处理,在接口中进行了登录者信息接口的调用,获取方式是从当前登录的requst中获取用户携带的session信息,在并行处理的过程中出现调用NPE异常信息。

问题排查:

  public static ServletRequestAttributes getRequestAttributes() {

           RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
          return (ServletRequestAttributes)attributes;
     }

上述方法中 RequestContextHolder.getRequestAttributes(); 获取到的是NULL对象,来源于

@Nullable
public static RequestAttributes getRequestAttributes() {
RequestAttributes attributes = (RequestAttributes)requestAttributesHolder.get();
if (attributes == null) {
attributes = (RequestAttributes)inheritableRequestAttributesHolder.get();
}

return attributes;
}
上述方法中获取方式:
(RequestAttributes)requestAttributesHolder.get();或者
RequestAttributes)inheritableRequestAttributesHolder.get();
出现了null空值,原因是子线程获取了当前线程组中的参数为空:
private static final ThreadLocal<RequestAttributes> requestAttributesHolder = new NamedThreadLocal("Request attributes");
private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder = new NamedInheritableThreadLocal("Request context");
具体的实现是:

public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
执行了最后的
setInitialValue();方法,此方法中返回了null;传递至其调用方法造成的NPE异常;
原因
  主线程中request对象在创建子线程并行执行的时候没有将request对象共享给子线程,导致的null空指针,具体原因可参考request和response设置的底层实现;
 /**
     * Bind the given RequestAttributes to the current thread.
     * @param attributes the RequestAttributes to expose,
     * or {@code null} to reset the thread-bound context
     * @param inheritable whether to expose the RequestAttributes as inheritable
     * for child threads (using an {@link InheritableThreadLocal})
     */
    public static void setRequestAttributes(@Nullable RequestAttributes attributes, boolean inheritable) {
        if (attributes == null) {
            resetRequestAttributes();
        }
        else {
            if (inheritable) {
                inheritableRequestAttributesHolder.set(attributes);
                requestAttributesHolder.remove();
            }
            else {
                requestAttributesHolder.set(attributes);
                inheritableRequestAttributesHolder.remove();
            }
        }
    }

    /**
     * Return the RequestAttributes currently bound to the thread.
     * @return the RequestAttributes currently bound to the thread,
     * or {@code null} if none bound
     */
    @Nullable
    public static RequestAttributes getRequestAttributes() {
              
        RequestAttributes attributes = requestAttributesHolder.get();
        if (attributes == null) {
            attributes = inheritableRequestAttributesHolder.get();
        }
        return attributes;
    }

解决办法
  1.监听所有的请求,以监听器处理;初始化的时候添加请求监听器;

             /**
               * 监听器:监听HTTP请求事件
               * 解决RequestContextHolder.getRequestAttributes()空指针问题
               * @return
               */
           @Bean
           public RequestContextListener requestContextListener(){
                 return new RequestContextListener();
            }

  2.将当前线程的变量共享给子线程;并行请求开始的前先做变量共享。
ServletRequestAttributes servletRequst= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
RequestContextHolder.setRequestAttributes(servletRequst,true);

 

 

 

 


  


  

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们