• Spring中子线程获取RequestAttributes


    一、问题

    在子线程中使用下面的方法获取 requestAttributes 为空。

    RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
    
    • 1

    二、解决方法

    这里提供两种解决方法,方法一适用于某个请求的业务方法;方法二具有通用性,适用于整个项目。

    注意:以下两种解决方法,需要在 Servlet 的生命周期内使用,否则会导致 requestAttributes 中获取到的属性为空。

    1、方法一

    在子线程启动前,加入下面的代码,可以使 requestAttributes 被子线程继承。

    // 使子线程也能获取到 requestAttributes
    RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
    RequestContextHolder.setRequestAttributes(requestAttributes, true);
    
    • 1
    • 2
    • 3

    2、方法二

    添加一个配置类。

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.web.filter.RequestContextFilter;
    import org.springframework.web.servlet.DispatcherServlet;
    
    import javax.annotation.PostConstruct;
    
    /**
     * 子线程继承配置
     */
    @Component
    public class ThreadContextInheritableConfig {
        @Autowired
        RequestContextFilter requestContextFilter;
    
        @Autowired
        DispatcherServlet dispatcherServlet;
    
        @PostConstruct
        public void init() {
            // 设置线程继承属性为true,便于子线程获取到父线程的request,两个都设置为了保险。
            requestContextFilter.setThreadContextInheritable(true);
            dispatcherServlet.setThreadContextInheritable(true);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    三、原理

    Servlet 初始化时,会调用 FrameworkServlet 中的 initContextHolders 方法。

    这个方法会设置 requestAttributes ,因为 private boolean threadContextInheritable = false; 所以 requestAttributes 不会被子线程继承。

    如果 requestAttributes 需要被子线程继承,就需要设置 threadContextInheritable 为 true 即可。

    	private void initContextHolders(HttpServletRequest request,
    			@Nullable LocaleContext localeContext, @Nullable RequestAttributes requestAttributes) {
    
    		if (localeContext != null) {
    			LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);
    		}
    		if (requestAttributes != null) {
    			RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    	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();
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    四、参考

    springcloud分布式子线程调用feign接口问题

    https://blog.csdn.net/u010715243/article/details/109571727

    异步线程RequestContextHolder为空问题

    https://blog.csdn.net/progammer10086/article/details/109217002

  • 相关阅读:
    公共政策学考试题库
    CSS基础11-视差滚动
    Spring Boot+Vue3前后端分离实战wiki知识库系统之前后端交互整合
    整理了一份ECS夏日省钱秘籍,这次@老用户快来领走
    自动化测试如何区分用例集合及编写规范
    【JavaEE】Spring 事务传播机制
    更新电脑显卡驱动的操作方法有哪些?
    软件测试月薪28K大厂面试题 (经面试官允许可以拿走试卷)
    Allegro给pin添加花连属性操作指导
    十四天学会C++之第三天(数组和字符串)
  • 原文地址:https://blog.csdn.net/qq_25775675/article/details/125617310