
Spring Annotation: Scope
最近遇到一個Spring使用錯誤的情境,造成營運問題…… 這個錯誤事後想想很簡單,都覺得早可以避免。
背景知識可以看這篇,簡單說就是每個Request連上來,Controller不存在的話,Spring 會建一個Controller。過一陣子沒人用就GC掉,否則會共用。所以Controller必須是Stateless的。(而且要threadsafe)
Controller's life-cycle in Spring MVC
Thanks for contributing an answer to Stack Overflow! Please be sure to answer the question. Provide details and share…stackoverflow.com
錯誤的code示意
描述:Controller內有一個Autowired的Handler。呼叫 Autowired Handler.setdata(data)然後 Autowired Handler.handle()
對於每個Client 去使用controller,現在會用到同一個handler。A使用完setdata,B拿去process,結果就是錯誤。
目前想到四種作法
- 使用ProxyMode
參考 https://zhuanlan.zhihu.com/p/27971569, Value可以依自己狀況設定,有Session, Request等等context。
這樣設定後,Controller依然會共用。但每個request會使用到不同的handler。
2.使用Spring Context
上面提到Controller聲明Autowired handler後,Handler寫@Scope(“protype),這樣是行不通的。Controller中可以改成
(handler那邊也需要修改成讓Spring知道有這個bean)
3.Controller不共用
直接在Controller外面加上@Scope(“prototype”)
缺點就是每個client都一個controller也一個Handler,memory使用量高。Stateless的物件不需要這樣。
4.Handler 寫成Stateless
應是最好的做法,Controller和Handler都共用,效能最佳。
但改動的code比較多,要改太多業務邏輯的code,測試很耗時,需緊急修正的狀況下就不採用。
Handler內不應該有任何跟request的data有關的class variable,應該要做成handler.process(data),並且中間沒有任何暫存變數。而且handler裡面肥肥的,有email、cac
最後,找出解法不會花很久,使用任一解法,然後搭配一些instance log機制確認每次request都有不同handler(最後是先用第3種,這系統效能暫時沒問題)
但要撈出因為錯誤而造成的資料錯誤夠難,各種撈log、 sql語法的考驗,辛苦負責的同事惹….
Comment…