Spring 中 HttpServletRequest 作为成员变量是安全的吗?

        在使用spring框架开发的时候,经常会在controller类中看到 HttpServletRequest 对象参数,一般我们都是直接使用,但是它是何时、怎么注入到 spring 容器的呢 ?另外以成员变量注入的 request 是线程安全的吗 ?

@Controller
public class SomeController {@Resourceprivate HttpServletRequest request1;@RequestMapping("/test")public String test2(HttpServletRequest request2) {System.out.println(request1.getQueryString());System.out.println(request2.getQueryString());return "";}}

 1、request 成员变量是否线程安全 ?

       先说结论:注入request这个成员变量是线程安全的,来看下 spring 是如何做到的,先 debug 看下两种做法真实注入类的区别

      可以看出成员变量注入的是代理对象AutowireUtils.ObjectFactoryDelegatingInvocationHandler ,而作为方法参数注入的就是我们一般使用的Request对象,先看下 AutowireUtils 的内部类ObjectFactoryDelegatingInvocationHandler

/*** Reflective InvocationHandler for lazy access to the current target object.*/
@SuppressWarnings("serial")
private static class ObjectFactoryDelegatingInvocationHandler implements InvocationHandler, Serializable {private final ObjectFactory<?> objectFactory;public ObjectFactoryDelegatingInvocationHandler(ObjectFactory<?> objectFactory) {this.objectFactory = objectFactory;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String methodName = method.getName();if (methodName.equals("equals")) {// Only consider equal when proxies are identical.return (proxy == args[0]);} else if (methodName.equals("hashCode")) {// Use hashCode of proxy.return System.identityHashCode(proxy);} else if (methodName.equals("toString")) {return this.objectFactory.toString();}try {return method.invoke(this.objectFactory.getObject(), args);}catch (InvocationTargetException ex) {throw ex.getTargetException();}}
}   

        当代理对象的方法被调用时,除去少数几个方法,大部分的情况都是通过this.objectFactory.getObject() 获取被代理对象,再调用被代理对象的相应方法

        进一步 debug,终于看到了熟悉的Request类,可以看到它是从 requestAttributesHolder 中取到的,那么requestAttributesHolder又是什么?

        RequestContextHolder的ThreadLocal成员变量就是实现的关键所在,它存放了每个线程对应的Request对象,因此在@Controller中调用作为成员变量注入的代理类的方法时,最终可以取到当前线程相对应的Request对象,并调用Request对应的方法,这样@Controller中的成员变量不需要重复注入(它一直都是最初bean初始化时注入的代理类),也避免了线程不安全的问题。

2、spring是何时将Request放入这个ThreadLocal之中的 ?      

        同样先说结论:在 Springmvc 的 dispatcherServlet 的父类 FrameworkServlet 里完成的,分析代码实现

        所有的请求调用到 Servlet 的doGet、dePost 时,最终都会通过 processRequest(request, response) 进行处理

        processRequest 方法在调用了 initContextHolders(request, localeContext, requestAttributes) 时会将Request放入ThreadLocal,方便后续线程安全的获取

3、总结

        1、在bean中注入成员变量 HttpServletRequest 时,实际注入的是 spring 框架生成的代理对象 ObjectFactoryDelegatingInvocationHandler 的实例。在我们实际调用这个成员变量的方法时,会调用 objectFactory 的 getObject() 对象对应的方法(objectFactory 是RequestObjectFactory 这个类的对象)

        2、RequestObjectFactory 的 getObject 方法是从RequestContextHolderthreadlocal 中去取值的。

        3、请求刚进入 springmvc 的 dispatcherServlet 时,会把 request 相关对象设置到RequestContextHolder 的 threadlocal 中去,方便后续线程安全的获取

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/413056.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SqlAlchemy使用教程(三) CoreAPI访问与操作数据库详解

SqlAlchemy使用教程(一) 原理与环境搭建SqlAlchemy使用教程(二) 入门示例及编程步骤SqlAlchemy使用教程(三) CoreAPI访问与操作数据库详解SqlAlchemy使用教程(四) MetaData 与 SQL Express Language 的使用SqlAlchemy使用教程(五) ORM API 编程入门 三、使用Core API访问与操作…

计算机网络——运输层(1)暨小程送书

计算机网络——运输层&#xff08;1&#xff09;暨小程送书 小程一言专栏链接: [link](http://t.csdnimg.cn/ZUTXU) 运输层概述两个主要协议运输层和网络层的关系网络层运输层总结 多路复用与多路分解多路复用多路分解不同的技术实现时分复用&#xff08;TDM&#xff09;频分复…

C语言从入门到实战——结构体与位段

结构体与位段 前言一、结构体类型的声明1.1 结构体1.1.1 结构的声明1.1.2 结构体变量的创建和初始化 1.2 结构的特殊声明1.3 结构的自引用 二、 结构体内存对齐2.1 对齐规则2.2 为什么存在内存对齐2.3 修改默认对齐数 三、结构体传参四、 结构体实现位段4.1 什么是位段4.2 位段…

【C语言】- 设置控制台文字颜色、大小和字体

【C语言】- 设置控制台标题、编码、文字颜色、大小和字体 文章目录 【C语言】- 设置控制台标题、编码、文字颜色、大小和字体1 - 设置控制台标题2 - 设置控制台编码3 - 设置控制台字体和大小参考链接 1 - 设置控制台标题 因为要用到 Windows API&#xff0c;所以需要包含头文件…

C++大学教程(第九版)5.19求Π的值

题目 代码 #include <bits/stdc.h> using namespace std;int main() {double pai 0;for (int count 1, i 1; count < 1000; i 2, count){int flag 1;if (count % 2 0){flag -1;}pai flag * (4.0 / (i * 1.0));cout << "当取前" << co…

西门子1200和西门子200smart S7通讯

S7通讯是西门子以太网络通讯中最简单最常用的通讯。 下面来介绍200smart和1200之间如何进行S7通讯: 由于200smart和1200使用不同的编程软件&#xff0c;所以只能使用单端组态&#xff0c;我们这里以1200为客服端组态。 1.首先打开博图软件添加1200设备&#xff0c;这里选择1…

(C语言)冒泡排序

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>//实现buble_sort函数&#xff1b; void buble_sort(int arr[], int sz) {//初始化变量值&#xff1b;int i 0;//嵌套循环冒泡排序&#xff1b;//外层循环&…

无人售卖饮品机的优势与选购指南

无人售卖饮品机作为一种新型的自动售货设备&#xff0c;已经越来越受到人们的关注和喜爱。它具有许多优势&#xff0c;为消费者提供了更加便捷、高效的购买体验。同时&#xff0c;面对市场上琳琅满目的无人售卖饮品机&#xff0c;如何挑选适合自己的产品也成为了消费者关心的问…

2018年认证杯SPSSPRO杯数学建模B题(第一阶段)动态模糊图像全过程文档及程序

2018年认证杯SPSSPRO杯数学建模 B题 动态模糊图像 原题再现&#xff1a; 人眼由于存在视觉暂留效应&#xff0c;所以看运动的物体时&#xff0c;看到的每一帧画面都包含了一段时间内 (大约 1/24 秒) 的运动过程&#xff0c;所以这帧画面事实上是模糊的。对电影的截图来说&…

Docker 安装 CentOS

Docker 安装 CentOS CentOS&#xff08;Community Enterprise Operating System&#xff09;是 Linux 发行版之一&#xff0c;它是来自于 Red Hat Enterprise Linux(RHEL) 依照开放源代码规定发布的源代码所编译而成。由于出自同样的源代码&#xff0c;因此有些要求高度稳定性…

rt-thread修改全局中断屏蔽函数,解决内核频繁关闭中断影响精密计时问题

带rtt-nano实时操作系统的小板子需要读取单总线设备&#xff0c;使用软件延时吧&#xff0c;总是由于时隙不精确&#xff0c;通信不稳定。按说不稳定情况也不频繁&#xff0c;但考虑到未来需要对上百、上千米外的单总线设备通信&#xff0c;开发的时候偷个懒&#xff0c;到应用…

Go新项目-为何选Gin框架?(0)

先说结论&#xff1a;我们选型Gin框架 早在大概在2019年下旬&#xff0c;由于内部一个多线程上传的需求&#xff0c;考虑到Go协程的优势&#xff1b; 内部采用Gin框架编写了内部的数据上传平台BAP&#xff0c;采用GinVue开发&#xff0c;但前期没考虑到工程化思维&#xff0c;导…