RequestContextHolder跨线程获取不到requests请求对象的解决方法

这篇具有很好参考价值的文章主要介绍了RequestContextHolder跨线程获取不到requests请求对象的解决方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、前言

最近在做一个项目,有个比较耗时的操作是启用线程进行异步操作,当时在启用的线程时,突然发现子线程无法获取父线程中的HttpServletRequest请求对象,因为是第一次遇到这种问题,所以记录一下解决方案。

二、问题模拟

在这里,我们简单模拟一下出现的问题。我们首先编写一个简单的hello请求,代码如下:

 /**
     * 主线程获取
     * @return
     */
    @GetMapping("/hello")
    public String hello() {
        String name = "";
        HttpServletRequest request = RequestUtils.getRequest();
        if (null == request) {
            log.info("未获取到request对象!");
        } else {
            name = request.getParameter("name");
            log.info("获取到的内容为{}", name);
        }

        return "hello";
    }

这是一个正常的请求,我们启动项目,访问接口地址。
RequestContextHolder跨线程获取不到requests请求对象的解决方法
RequestContextHolder跨线程获取不到requests请求对象的解决方法

从上图中,我们不难发现,我们成功的拿到了HttpServletRequest中的参数。

接着,我们稍微修改一下我们的代码,另起一个线程,在子线程中获取HttpServletRequest中的name属性,代码如下:

 /**
     * 主线程获取
     * @return
     */
    @GetMapping("/hello")
    public String hello() {

        new Thread(() -> {
            HttpServletRequest request = RequestUtils.getRequest();
            if (null == request) {
                log.info("未获取到request对象!");
            } else {
                String name = request.getParameter("name");
                log.info("获取到的内容为{}", name);
            }
        }).start();


        return "hello";
    }

我们再次启动项目并访问接口地址:
RequestContextHolder跨线程获取不到requests请求对象的解决方法
RequestContextHolder跨线程获取不到requests请求对象的解决方法

我们发现,这时候的request对象已经变为空,我们根本没办法获取请求中的name属性。

结论:如果采用多线程,我们就获取不到父线程中的HttpServletRequest对象了。

三、解决方法

解决上面的问题其实很简单,只需要在开启子线程时,调用一下 RequestContextHolder.setRequestAttributes(requestAttributes, true);方法,将第二个参数设为true就可以了。

我们修改上面的代码如下:

/**
     * 主线程获取
     * @return
     */
    @GetMapping("/hello")
    public String hello() {
        /**
         * 解决子线程无法获取HttpServletRequest请求对象中数据的问题
         */
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        RequestContextHolder.setRequestAttributes(requestAttributes, true);
        new Thread(() -> {
            HttpServletRequest request = RequestUtils.getRequest();
            if (null == request) {
                log.info("未获取到request对象!");
            } else {
                String name = request.getParameter("name");
                log.info("获取到的内容为{}", name);
            }
        }).start();


        return "hello";
    }

启动项目,访问接口地址,结果如下:
RequestContextHolder跨线程获取不到requests请求对象的解决方法
RequestContextHolder跨线程获取不到requests请求对象的解决方法
可以发现,我们可以在子线程中获取HttpServletRequest对象了。

四、原理

点开RequestContextHolder.setRequestAttributes(requestAttributes, true)方法,查看源码:

	/**
	 * 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();
			}
		}
	}

这个方法很简单,主要只要继续查看requestAttributesHolderinheritableRequestAttributesHolder这两个类的继承关系就可以了。

requestAttributesHolder

private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
			new NamedThreadLocal<>("Request attributes");


public class NamedThreadLocal<T> extends ThreadLocal<T> {}

我们发现,requestAttributesHolder对象类型为NamedThreadLocal,NamedThreadLocal父类是ThreadLocal。

inheritableRequestAttributesHolder

private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
			new NamedInheritableThreadLocal<>("Request context");

public class NamedInheritableThreadLocal<T> extends InheritableThreadLocal<T> {}

我们发现inheritableRequestAttributesHolder的类型为NamedInheritableThreadLocal,NamedInheritableThreadLocal是InheritableThreadLocal的子类。

看到这里,就很清晰了。调用RequestContextHolder.setRequestAttributes(requestAttributes, true)这个方法,将原本放在ThreadLocal对象中的属性放到了类型为InheritableThreadLocal的对象中了,所以我们启动的子线程可以获取到父线程中的属性。

五、总结

当子线程中无法获取父线程中的HttpServletRequest的方法时,我们可以通过调用RequestContextHolder.setRequestAttributes(requestAttributes, true)方法,使得子线程也可以获取父线程中HttpServletRequest对象。文章来源地址https://www.toymoban.com/news/detail-544592.html

到了这里,关于RequestContextHolder跨线程获取不到requests请求对象的解决方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Javaweb——Request通用方式获取请求参数

    在旧的请求参数的获取方式当中,需要对两种不同的请求方式做两份不同的代码逻辑,现在就是要统一操作,比如在post里面调用get的代码   如下图的操作 先获取请求方式,对于不同的方式都先把请求参数获取出来,这里request还完成了对字符串的解析,对和=进行切割 之后将

    2024年02月13日
    浏览(51)
  • SpringBoot获取Request请求的三种方式

    Request对象包含了请求的各种信息,比如请求方法、请求URL、请求参数、请求内容等等,这些信息可以供服务器进行处理和响应。那么在SpringBoot中,怎么才能获取到Request对象? 本文将介绍三种方法,并提示例参考。 一、直接在Controller方法参数上注入HttpServletRequest 这是最常用

    2024年02月04日
    浏览(56)
  • nginx反代后java的request.getScheme获取不到https的解决办法

    在实际应用中,经常会用到nginx反向代理应用,这中就会出现一中情况,访问https页面Java 通过request.getScheme()获取不到https协议,或者response.sendRedirect重定向是http,而不是我们想要的https。 经过反代后,协议信息没有转发到后端,或者后端没有设置protocolHeader 需要在nginx的配置

    2024年02月12日
    浏览(37)
  • 06-HTTP-Request获取请求头数据方法

    1、getHeader()方法用于获取指定名称的HTTP请求头的值。 getHeader()方法的参数为一个字符串,表示要获取的HTTP请求头的名称。方法返回一个字符串,表示该HTTP请求头的值。如果指定名称的HTTP请求头不存在,则返回null。 常见的HTTP请求头有: Accept:指定客户端可以接受哪些类型

    2024年02月16日
    浏览(46)
  • 通过 Request 请求获取真实 IP 地址以及对应省份城市

    title: 通过 Request 请求获取真实 IP 地址以及对应省份城市和系统浏览器信息 date: 2022-12-16 16:20:26 tags: GeoIP2 UserAgentUtils categories: 开发实践 cover: https://cover.png feature: false 代码如下,这里的 CommonUtil.isBlank() 为封装的判空方法 1、首先,获取 X-Forwarded-For 中第 0 位的 IP 地址,它在

    2024年02月01日
    浏览(52)
  • selenium自动获取cookies用于requests做接口请求爬虫

    目录 一、思想 二、代码          有关爬虫一些报错解决,或是爬虫工具的使用及其他问题的,可以看看我的爬虫专栏:博主_zkkkkkkkkkkkkk的爬虫专栏 一、思想         selenium可以用来模拟用户操作的python第三方包,而requests则是用来做接口请求。两者一结合,可能在某些

    2024年02月16日
    浏览(43)
  • 【Java 进阶篇】Java Request 获取请求体数据详解

    在Java Web开发中,获取HTTP请求的请求体数据是一项常见任务。HTTP请求的请求体通常包含了客户端提交的数据,例如表单数据、JSON、XML等。在Java中,可以使用 HttpServletRequest 对象来获取HTTP请求的请求体数据。本文将详细解释如何使用Java获取HTTP请求的请求体数据,并提供示例

    2024年02月03日
    浏览(40)
  • 【Java 进阶篇】Java Request 获取请求参数的通用方式详解

    在Java Web开发中,获取HTTP请求的参数是一项基本任务。请求参数可以包含在URL中,也可以包含在请求体中,例如表单提交时的参数。在Java中,可以使用 HttpServletRequest 对象来获取HTTP请求的参数。本文将详细解释如何使用Java获取HTTP请求的参数,包括通用的方式以及示例代码。

    2024年02月05日
    浏览(42)
  • postman的Pre-request Script获取请求体参数

    一、请求体为raw 二、请求体为x-www-form-urlencoded 三、请求体为form-data

    2024年02月12日
    浏览(59)
  • Springboot3.2.0使用RequestContextHolder获取HttpServletRequest为NULL

    在之前的版本中一般为了能在任意地方都能获取到HttpServletRequest我们一般都会自己封装工具类从 RequestContextHolder 中获取到 但是在新版的SpringBoot3.2.0版本中这种方式获取到的 ServletRequestAttributes 是null,点击进去RequestContextHolder查看源代码发现少了依赖 即使我在pom中加入的响应

    2024年04月13日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包