日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring MVC 成员变量 request 线程安全问题的讨论

發布時間:2023/12/15 javascript 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring MVC 成员变量 request 线程安全问题的讨论 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2019獨角獸企業重金招聘Python工程師標準>>>

?

作者:wangxinxi

?

? ?最近有人問我,Spring MVC Controller的成員變量@Resource private HttpServletRequest request,這樣用會不會產生線程安全問題。咋一想Spring MVC 的 Controller默認是單例,成員變量request應該會導致線程安全問題,那么真的是這樣的?

?

已知一個Spring MVC的Controller, 用戶的控制器

代碼如下:

@Controller

@RequestMapping("/user")

public class UserController {

?

private HttpServletRequest request1;

?

@Resource

private HttpServletRequest request2;

?

@ModelAttribute

public void setRequest1(HttpServletRequest request) {

??? this.request1 = request;

}

?

@RequestMapping("/test")

public void testRequest(){

??? System.out.println(request1.getParameter("test"));

??? System.out.println(request2.getParameter("test"));

}

?

那么request1和request2, 在高并發下是線程安全性的?

先說答案:request1非線程安全,而request2是線程安全

?

眾所周知,在 Controller 是單例的情況下,成員變量一般不是線程安全的(即多個線程共享一個成員變量), 但是request2卻是線程安全的, 為什么?

?

request1非線程安全我們絲毫不懷疑:

假設有用戶甲和乙同事并發的訪問user/test接口,甲和乙都會把自己的request賦值給request1。當甲使用request1的時候, 乙可以把乙的request賦值給成員變量request1,但是甲這時候使用的就是乙的request了,就有可能導致安全問題。

?

但是request2僅僅加上了一個注解"@Resource"就變成了線程安全的。

所以我決定分析一下,下圖是用idea調試模式,很容易發現, 接口request1的 多態是基于WebAPP容器的RequestFacade,對與當前的環境具體是指Tomcat對HttpServletRequest 的門面模式的實習;接口request2是$Proxy15,這個是啥東西?明眼的人一眼就看出了, 這個是基于JDK動態代理生成的代理類,生成代理類型的規則是$ProxyN, 如果不知道JDK的動態代理請自行Google。

?

?

?

繼續分析request2,代理類的InvocationHandler是AutowireUtils的內部類ObjectFactoryDelegatingInvocationHandler,這一切都是怎么發生的?

尋蹤溯源

?

1、Spring 實例化Bean的時候,發現有一個@Resource private HttpServletRequest request2;需要注入,需要進行注入處理

?

如果類型是

這8種接口, 需要特殊處理,包含javax.servlet.http.HttpServletRequest,被映射成WebApplicationContextUtils.RequestObjectFactory這個是生產Request的工廠類,這個工廠就是生產ServletRequest的,其源代碼如下:

?

然后通過JDK動態代理生成HttpServletRequest的代理類

?

ObjectFactoryDelegatingInvocationHandler 動態代理的具體實現

?

最后完成對request2注入。

?

2、粗略看注入流程,除了特殊處理HttpServletRequest之外沒有什么特殊的。

然而我們在看看WebApplicationContextUtils.RequestObjectFactory的getObject()方法

通過currentRequestAttributes方法拿到了ServletRequestAttributes,最后通過ServletRequestAttributes拿到了HttpServletRequest。

?

下面我們分析一下currentRequestAttributes方法

接著調用了RequestContextHolder.currentRequestAttributes();

然后調用了

最后是通過requestAttributesHolder拿到了HttpServletRequest。

我們再來看看requestAttributesHolder是什么鬼?

?

?

我們驚奇的發現requestAttributesHolder是ThreadLocal<RequestAttributes>,有了ThreadLocal這個神器,RequestAttributes綁定著了HttpServletRequest,難怪可以保證@Resource private HttpServletRequest request2;這個線程安全,自此真相大白。

RequestAttributes是如何綁定HttpServletRequest的?

在web.xml配置的監聽器

<listener>

<listener-class>

org.springframework.web.context.request.RequestContextListener

</listener-class>

</listener>

?

通過HTTP請求時的監聽器進行的配置,在這個請求的上下文中都可以得到這個request

?

這里講一下,ThreadLocal的作用是提供線程內的局部變量,這種變量在多線程環境下訪問時能夠保證各個線程里變量的獨立性。更多關于ThreadLocal知識請自行google。

?

簡而言之,Spring MVC在 Controller 是單例的情況下,會對HttpServletRequest等需要注入的接口做特殊處理,通過JDK的動態代理的方式和ThreadLocal對應的線程變量綁定,從而保證線程安全。所以在Controller等其他的請求上下文中放心的使用@Resource private HttpServletRequest request吧。

?

希望對您有所幫助

?

轉載于:https://my.oschina.net/u/270991/blog/1785896

總結

以上是生活随笔為你收集整理的Spring MVC 成员变量 request 线程安全问题的讨论的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。