成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

99%的人都答錯了!Spring MVC 控制器到底是不是單例?怎么破局?

開發 前端
如果每來一個請求就 new 一個 Controller,想想服務器內存得爆炸成啥樣子?而且 Controller 通常是無狀態的(處理邏輯、調用 Service),并不需要為每次請求新建實例。

引言

嗨大家好呀,我是小米,一個喜歡邊學邊分享,把坑踩過一遍再告訴你怎么繞開的技術宅控!

最近我在準備換工作的社招面試,被問了一個超級經典但又能坑死人的問題:

Spring MVC 的控制器(Controller)是單例的嗎?如果是,會有什么問題?怎么解決?

聽到這個問題那一刻,我表面微笑,內心咯噔:

“完了,要是答得不清不楚,面試官又要畫叉叉了……”

好在我之前踩過這個坑,一口氣講了個通透,還得到了面試官的點贊!

今天我就把完整的故事和解題思路分享給大家。

記憶中的第一個坑:Controller 的單例本質!

記得我剛學 Spring MVC 的時候,腦子里想當然覺得:

“控制器嘛,就是處理一個請求,創建一個對象,處理完就丟掉,多清晰!”

結果呢?查源碼一看,啪啪打臉!

實際上,Spring MVC 默認把 Controller 當作單例(Singleton)來管理的!

也就是說,咱們寫的這個:

圖片圖片

默認是單例模式(Singleton Scope),由 Spring 容器托管,啟動時創建一個實例,整個應用生命周期共用這一份!

所以,記住一句話:

Spring 中的 @Controller 本質上是一個單例 Bean!

那為啥 Spring 要這么搞呢?

其實很簡單,節省資源,提高性能!

如果每來一個請求就 new 一個 Controller,想想服務器內存得爆炸成啥樣子?而且 Controller 通常是無狀態的(處理邏輯、調用 Service),并不需要為每次請求新建實例。

所以,單例是合理的默認選擇!

但是——

事情到這里,才剛剛開始。

單例帶來的隱患:線程安全問題!

單例 + 多線程,聽著就危險,對吧?

沒錯,Controller 是單例,但是 用戶請求是多線程并發的。

一旦 Controller 里寫了成員變量,而且這個成員變量又是可變的、共享的,那簡直是災難現場!

比如:

圖片圖片

看著沒啥問題對吧?

但是注意啊!

  • 用戶A提交了一個orderId:1001
  • 用戶B緊接著提交了一個orderId:1002
  • 因為Controller是單例的,他們共用同一個 lastOrderId!

結果:

A本來想處理自己提交的1001,結果處理到一半,lastOrderId 被 B 改成了1002……

數據錯亂、請求串臺、詭異Bug,分分鐘爆炸!

這就是典型的線程安全問題!

總結一下:

Spring MVC Controller 單例本身沒問題,問題在于如果 Controller 里保存了【有狀態的可變成員變量】,就會引發線程安全問題!

面試官想聽的:怎么解決?

好,既然知道問題了,那接下來最重要的就是——怎么解決?

思路一:保證 Controller 無狀態

  • 不要在 Controller 里寫可變的成員變量!
  • 所有數據都通過方法參數傳遞。

比如剛才的 lastOrderId,正確寫法應該是:

圖片圖片

這樣,每個請求進來,拿的是自己方法參數里的數據,不會互相污染。

記住一句話:

Controller 要像一潭死水一樣冷靜,不要有變化,保持無狀態!

思路二:必要時改變作用域

如果業務場景確實需要保存一些請求級別的數據,比如一步步流程操作,那么可以考慮改變 Bean 的作用域!

  • 使用 @Scope("request")
  • 讓每個請求有自己的 Controller 實例。

比如:

圖片圖片

加上 @Scope("request"),

Spring 會給每個請求創建一個新的 Controller 實例,互不影響!

當然啦,這樣就失去了單例帶來的性能優勢了,要慎重選擇。

大部分場景下,通過方法參數傳遞就夠了,很少需要改變作用域。

思路三:使用 ThreadLocal

如果真的需要存 per-request 數據,還可以用ThreadLocal。

圖片圖片

ThreadLocal 保證每個線程有獨立副本,互不干擾。

注意,用完一定要 remove()!不然可能會導致內存泄漏,尤其是在線程池環境下。

小米的社招總結答法(親測有效)

最后,總結一下,社招面試我怎么答的:

面試官問:“Spring MVC 控制器是單例的嗎?如果是,有什么問題?怎么解決?”

我答:

  • Spring MVC 的控制器默認是單例的,由 Spring 容器管理。
  • 單例本身沒問題,但如果 Controller 里存在可變的成員變量,在多線程并發請求下會引發線程安全問題。
  • 解決辦法有:
  • 或者使用 ThreadLocal 保存每個請求的獨立數據,但注意清理。
  • 必要時可以將 Controller 設為請求作用域(@Scope("request"));
  • 最推薦:保持 Controller 無狀態,只通過方法參數傳遞數據;

面試官點頭微笑,

我心里一陣狂喜,暗搓搓給自己比了個??。

總結一下今天的故事

今天我們講了:

  • Spring MVC 控制器是默認單例的(Singleton Scope);
  • 單例會引發線程安全問題(成員變量共享導致數據錯亂);
  • 最好保持 Controller 無狀態;
  • 特殊場景下可以使用 @Scope("request") 或 ThreadLocal;

關鍵思路:

  • Controller 要無狀態,數據傳參走,線程安全穩如老狗!
責任編輯:武曉燕 來源: 軟件求生
相關推薦

2024-05-07 13:29:00

CSS選擇器權重

2019-06-06 08:30:07

區塊鏈數字貨幣比特幣

2012-07-02 09:40:45

小米手機

2021-01-11 05:37:54

倉儲模式接口

2020-02-25 16:30:36

MD5是不是加密

2016-09-23 15:10:10

HTTPGETPOST

2019-02-27 09:28:15

Redis服務器事務

2024-07-05 09:00:00

編程語言Rust開發

2019-05-15 16:15:08

HTTPGETPOST

2024-09-04 01:36:51

Java對象傳遞

2011-03-08 08:58:37

springmvc

2021-08-02 14:48:15

云電腦Windows 365華為

2025-03-11 08:20:00

C++main函數

2016-12-23 09:04:56

大數據技術BAT

2019-12-16 09:42:38

PHP語言程序員

2022-08-04 08:23:13

顯示器色域參數

2009-01-12 11:16:58

控制器控制器行為行為結果

2023-10-12 08:54:20

Spring事務設置

2021-04-13 10:35:13

網盤存儲硬盤

2021-03-10 13:42:27

筆記本雙屏設計
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩一区二区在线看 | 狠狠躁夜夜躁人人爽天天高潮 | 亚洲欧美日韩精品久久亚洲区 | 亚洲人精品午夜 | 超碰免费在线观看 | 国产一区www | 欧美黄色免费网站 | 亚洲国产精品成人 | 91精品国产乱码久久久久久久久 | 中文字幕一区二区三区乱码图片 | 午夜电影福利 | 欧美精品在欧美一区二区 | 亚洲一区二区三区视频免费观看 | 精品欧美一区二区中文字幕视频 | 精品国产亚洲一区二区三区大结局 | 久久精品伊人 | 精品一区二区三区在线观看 | 久久久www成人免费无遮挡大片 | 精品一区电影 | 中文字幕乱码一区二区三区 | 国产精久久久久久久妇剪断 | 亚洲欧美中文字幕 | ww亚洲ww亚在线观看 | 久久中文字幕在线 | 亚洲视频免费观看 | 亚洲精品九九 | 一区二区三区高清在线观看 | 欧美日韩精品一区二区三区视频 | 午夜爱爱毛片xxxx视频免费看 | 国产毛片久久久久久久久春天 | 春色av| 欧美一级片a | 国产精品久久久久久 | a级在线免费视频 | www国产亚洲精品久久网站 | 成年免费大片黄在线观看一级 | 久久成人精品 | 岛国毛片| 日韩精品一区二区三区中文字幕 | 日韩av一区二区在线观看 | 久久精品国产久精国产 |