美文网首页
使用RequestContextHolder.getReques

使用RequestContextHolder.getReques

作者: martin6699 | 来源:发表于2019-10-01 06:40 被阅读0次

    注意事项:

    1. 不要在请求方法里另起一个子线程调用该方法;
    2. 在请求周期中,尽可能不要传递Request实例给多线程使用,因为子线程可能在Request生命周期结束销毁后再使用Request时获取不了参数,否则必须同步线程 让其在生命周期结束前调用;

    在Spring Boot中,如果我们要获取当前Request实例,可以通过以下这个方法获取。

    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    

    使用这种方法获取的时候需要注意使用多线程会出现些状况,例如一个请求过来后,请求达到Service方法,然后Service方法里另起一个线程启动,在该线程run方法里面想要通过以上方法可能获取不到Request实例。
    且看RequestContextHolder内部分源码:

    
        private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
                new NamedThreadLocal<>("Request attributes");
    
        private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
                new NamedInheritableThreadLocal<>("Request context");
    
    .....
    
        /**
         * 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;
        }
    

    可看到之所以能通过静态方法getRequestAttributes获取Request实例,是因为ThreadLocal获取。一个请求到达容器后,Spring会把该请求Request实例通过setRequestAttributes方法 把Request实例放入该请求线程内ThreadLocalMap中,然后就可以通过静态方法取到。原理就是ThreadLocal,但ThreadLocal不能让子线程继承ThreadLocalMap信息,可以使用InherbritableThreadLocal实现子线程信息传递。
    但Spring Boot 默认使用ThreadLocal把Request设置进请求线程中,这样如果在请求方法里面另起一个子线程然后再通过getRequestAttributes方法获取,是获取不到的。
    所以要在能让子线程获取到,就可以使用InherbritableThreadLocal,看setRequestAttributes方法有这个布尔值可以设,至于在哪里设就没去深究。但个人认为最好不要修改该布尔值,默认就行,否则会有意向不到的可能

    相关文章

      网友评论

          本文标题:使用RequestContextHolder.getReques

          本文链接:https://www.haomeiwen.com/subject/oknfpctx.html