Spring 单例 httprequest 线程安全
@Autowired HttpServletRequest之所以线程安全是因为, httpsevletRequest 储存在 RequestContextHolder中。
- 每次http请求的doXXX 都会被FrameworkServlet拦截,通过 RequestContextHolder.setxxxxx 写入TheadLocal。
- Autowired 获取request的时候,通过RequestContextHolder.getxxx 从ThreadLocal中获取。
为什么Autowired HttpServletRequest是线程安全的,获取的方式
1. 启动断点调试,查看request的来源是 WebApplicationContextUtils.RequestObjectFactory.

2. 查看源码 WebApplicationContextUtils.RequestObjectFactory, request 来自于 RequestContextHolder.currentRequestAttributes() 方法
class WebApplicationContextUtils {
@SuppressWarnings("serial")
private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {
@Override
public ServletRequest getObject() {
return currentRequestAttributes().getRequest();
}
@Override
public String toString() {
return "Current HttpServletRequest";
}
}
private static ServletRequestAttributes currentRequestAttributes() {
RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
if (!(requestAttr instanceof ServletRequestAttributes)) {
throw new IllegalStateException("Current request is not a servlet request");
}
return (ServletRequestAttributes) requestAttr;
}
}
3. 上述方法的attributes来自于线程安全的ThreadLocal中的当前线程的HttpServletRequest
public abstract class RequestContextHolder {
private static final boolean jsfPresent =
ClassUtils.isPresent("javax.faces.context.FacesContext", RequestContextHolder.class.getClassLoader());
private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
new NamedThreadLocal<>("Request attributes");
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();
}
}
}
设置的方式
request是什么时候设置到threadlocal中去的呢? 是在Springmvc的dispatcherServlet的父类FrameworkServlet里操作的.。 doGet 、doPost 、doXXX方法都是委托processRequest方法去做的. 也就是说请求方法会被FrameworkServlet的processRequest拦截。
class FrameworkServlet {
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
.....
initContextHolders(request, localeContext, requestAttributes);
}
private void initContextHolders(HttpServletRequest request,
@Nullable LocaleContext localeContext, @Nullable RequestAttributes requestAttributes) {
......
if (requestAttributes != null) {
RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
}
....
}
}
参考
https://www.cnblogs.com/abcwt112/p/7777258.html
Spring 单例 httprequest 线程安全的更多相关文章
- Spring单例与线程安全小结
一.Spring单例模式与线程安全 Spring框架里的bean,或者说组件,获取实例的时候都是默认的单例模式,这是在多线程开发的时候要尤其注意的地方. 单例模式的意思就是只有一个实例.单例模式确 ...
- Spring单例Bean和线程安全
Spring的bean默认都是单例的,这些单例Bean在多线程程序下如何保证线程安全呢?例如对于Web应用来说,Web容器对于每个用户请求都创建一个单独的Sevlet线程来处理请求,引入Spring框 ...
- 002-创建型-03-单例模式(Singleton)【7种】、spring单例及原理
一.概述 保证一个类仅有一个实例,并提供一个全局访问点 私有构造器.线程安全.延迟加载.序列化和反序列化安全.反射攻击 1.1.适用场景 1.在多个线程之间,比如servlet环境,共享同一个资源或者 ...
- Spring单例 和 Scope注解
关键字 @Scope @Qualifier Singleton 单例 Spring是单例模式.结合Springboot的例子. Controller @Autowired private Tes ...
- 【转】Spring Bean单例与线程安全
一.Spring单例模式及线程安全 Spring框架中的Bean,或者说组件,获取实例的时候都是默认单例模式,这是在多线程开发的时候需要尤其注意的地方. 单例模式的意思是只有一个实例,例如在Sprin ...
- Spring Bean单例与线程安全
一.Spring单例模式及线程安全 Spring框架中的Bean,或者说组件,获取实例的时候都是默认单例模式,这是在多线程开发的时候需要尤其注意的地方. 单例模式的意思是只有一个实例,例如在Sprin ...
- Spring Controller单例与线程安全那些事儿
目录 单例(siingleton)作用域 原型(Prototype)作用域 多个HTTP请求在Spring控制器内部串行还是并行执行方法? 实现单例模式并模拟大量并发请求,验证线程安全 附录:Spri ...
- (转载)spring单例和多例详解。如何在单例中调用多例对象
spring生成对象默认是单例的.通过scope属性可以更改为多例. <bean id="user" class="modle.User" scope=& ...
- 有关线程安全的探讨--final、static、单例、线程安全
我的代码中已经多次使用了线程,然后还非常喜欢使用据说是线程不安全的静态方法,然后又看到很多地方最容易提的问题就是这个东西线程不安全 于是我不免产生了以下几个亟待解决的问题: 什么样的代码是天生线程 ...
随机推荐
- [php]文件下载简述
文件下载是通过网页页面链接跳转到后台php脚本处理,前台跳转链接代码如下: <a href="download.php?filename=hello.txt">down ...
- 用Nginx分流绕开Github反爬机制
用Nginx分流绕开Github反爬机制 0x00 前言 如果哪天有hacker进入到了公司内网为所欲为,你一定激动地以为这是一次蓄谋已久的APT,事实上,还有可能只是某位粗线条的员工把VPN信息泄露 ...
- linux挂载光盘
1.找到光盘的位置 ls -l /dev |grep cdrom mount /dev/sr0 /mnt [root@node2 /]# ls -l /dev |grep cdrom lrwxrwx ...
- select()函数用法三之poll函数
poll是Linux中的字符设备驱动中有一个函数,Linux 2.5.44版本后被epoll取代,作用是把当前的文件指针挂到等待队列,和select实现功能差不多. poll()函数:这个函数是某些U ...
- leetcode之 两数之和
# -*- coding: utf-8 -*- # @Time : 2018/9/27 21:41 # @Author : cxa # @File : twonum.py # @Software: P ...
- mysql命令补全工具
需要在linux中下载mysql插件. 安装mysql插件 yum -y install epel-release python-pip python-devel pip install mycli ...
- poj1063
题意:有一些珠子排成一圈,珠子有两种颜色:黑和白.每次操作可以调换中间隔着一个珠子的两珠子的位置,给出这个圈子的初始状态,问最终能否通过操作让圈子中所有同色的珠子排在一起,即黑白分开. 分析:分两种情 ...
- Flask:使用Eclipse+PyDev插件编辑基于package的项目
Windows 10家庭中文版,Python 3.6.4,Flask 1.0.2,Eclipse Oxygen.1a Release (4.7.1a),PyDev 6.3.2 本文记录了 使用Ecli ...
- 简单计算器的C实现-函数指针,main函数传参
/** 程序功能:简单计算器,实现加减乘除平方* 作者版本日期:2015.11.08 zhouhb OK* 源代码:李明 <新概念C语言培训>第33集 C语言Shell命令解释器的实现* ...
- 网络协议之NAT穿透
NAT IPv4地址只有32位,最多只能提供大致42.9亿个唯一IP地址,当设备越来越多时,IP地址变得越来越稀缺,不能为每个设备都分配一个IP地址.于是,作为NAT规范就出现了.NAT(Networ ...