Spring的Controller默認是單例還是多例


  Spring bean作用域

  先看看spring的bean作用域有幾種,它們之間分別有啥不同。Spring bean作用域有以下5個:

  • singleton:單例模式,默認,當spring創建applicationContext容器的時候,Spring會欲初始化所有的該作用域實例,加上lazy-init就可以避免預處理;
  • prototype:原型模式,每次通過getBean獲取該bean就會新產生一個實例,創建后Spring將不再對其管理;

  ******* 下面是在web項目下才用到的 ******* 

  • request:搞web的大家都應該明白request的域了吧,就是每次請求都新產生一個實例,和prototype的不同之處就是創建后接下來的管理,Spring依然在監聽;
  • session:每次會話,同上;
  • global session:全局的web域,類似於servlet中的application。 

  好了,上面都說了Spring的controller默認是單例,那很自然就是singleton了。 

  再通過一個例子看看單例會不會有如下問題——類中定義的非靜態變量線程安全問題。為什么Spring要默認是單例呢?原因有二:

  1、為了性能。這個不用廢話了,單例不用每次都new,當然快了。

  2、不需要多例。不需要多實例會讓很多人迷惑,因為Spring MVC官方也沒明確說不可以多例。

  我這里說不需要的原因是看開發者怎么用了,開發者如果在controller中定義很多的屬性,那么單例肯定會出現競爭訪問了。因此,只要controller中不定義屬性,那么單例完全是安全的。下面給個例子說明下:

import org.springframework.context.annotation.Scope; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/scopeTest") // @Scope("prototype")
public class ScopeTestController { private int num = 0; //非靜態成員變量
 @RequestMapping("/testScope") public void testScope() { System.out.println("testScope --> " + ++num); } @RequestMapping("/testScope2") public void testScope2() { System.out.println("testScope2 --> " + ++num); } }

  依次請求testScope()和testScope2()函數,執行結果是

testScope --> 1 testScope2 --> 2

  改為多例,即去掉@Scope("prototype")前面的注釋,則執行結果是

testScope --> 1 testScope2 --> 1

  相信大家不難發現 :單例是線程不安全的,會導致屬性重復使用。如果把num定義為類變量,無論是否使用多例模式,都會復用類變量,感興趣的小伙伴可以驗證一下。解決方案:

  1、不要在controller中定義成員變量。

  2、萬一必須要定義一個非靜態成員變量,則通過注解@Scope(“prototype”)將其設置為多例模式。

  3、在controller中使用ThreadLocal變量。

Reference

 https://www.cnblogs.com/zxf330301/articles/6105127.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM