成人免费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技術棧公眾號

主站蜘蛛池模板: 精品日韩一区 | 久久a久久 | 欧美精品一区在线观看 | 亚洲国产成人精品久久久国产成人一区 | 九九爱这里只有精品 | 日韩在线观看网站 | 国产免费看 | 精品国产一级片 | 精品国产91乱码一区二区三区 | 日韩欧美高清 | 国产午夜av片 | 久久免费福利 | 国产日韩欧美激情 | 午夜精品一区二区三区在线播放 | 91视视频在线观看入口直接观看 | 欧美精品一区二区蜜桃 | 欧美成人精品在线 | 欧美男人天堂 | 91视在线国内在线播放酒店 | 欧美中文字幕在线观看 | 日韩h | 观看av | 91视频免费黄 | 日韩中文字幕 | 日韩不卡三区 | 天天操网| www.色.com | 丁香五月网久久综合 | 日韩午夜精品 | 99久久精品国产一区二区三区 | 亚洲美女一区二区三区 | 精品一二三区 | 91视频www.| 欧美成人h版在线观看 | 日韩欧美在线视频观看 | 一区二区av| 亚洲一级淫片 | 国产午夜精品久久久 | 亚洲国产成人一区二区 | 欧美亚洲第一区 | 91精品国产综合久久精品 |