Sun River
          Topics about Java SE, Servlet/JSP, JDBC, MultiThread, UML, Design Pattern, CSS, JavaScript, Maven, JBoss, Tomcat, ...
          posts - 78,comments - 0,trackbacks - 0
          --Spring的singleton是容器級的,我們一般說的singleton模式是JVM級的。所以singleton模式中,singleton的class在整個JVM中只有一個instance,Spring的Bean,你可以一個class配置多個Bean,這個class就有了多個instance。這個singleton是指在spring容器中,這個Bean是單實例的,是線程共享的。所以要求這些類都是線程安全的。也就是說,不能出現修改Bean屬性的方法,當然除了設值得那些setter。只要滿足線程安全,這些bean都可以用singleton。而且我們在絕大多數使用上,也是這樣用的,包括dao,service。
          Beanfactory是Spring初始以靜態方式載入的,Spring的單例IOC是基于容器級的,所以這你都不用擔心與考慮.

          --應用中對象有兩種,行為對象和數據對象,行為對象都要求是線程安全的!也就是允許單例的, 不管是dao 還是 service 對象,都是行為對象,行為對象不應該引用非線程安全的對象做成員量,同時在應用外部的資源(如文件,數據庫連接,session)時,要先保證對這些東西的訪問是做了并發控制的!
            對于spring來講,<bean scope="singleton"/>或<bean singleton="true"/>都是保證對同一sesionfactory bean是單例的,也就是所謂 sessionfactory 范圍的.

          --這是一個真實的案例,我們在項目中使用Spring和ACEGI,我之所以選擇ACEGI,除了它對權限的良好控制外,
          我還看好它的SecurityContextHolder,通過代碼
          代碼
          1. Authentication auth = SecurityContextHolder.getContext().getAuthentication();   
          <script>render_code();</script>
          我可以很容易在系統任意一層得到用戶的信息,而不用把用戶信息在參數里傳來傳去,(這也是struts的缺點之一)
          但是我在每一次要得到用戶信息的時候都寫上面的一段代碼,未免有些麻煩,所以我在BaseService, BaseDao里都提供了如下方法:
          代碼
          1.  /**  
          2.  * get current login user info  
          3.  * @return UserInfo  
          4.  */  
          5. protected UserInfo getUserInfo()   
          6. {   
          7.     return getUserContext().getUserInfo();   
          8. }   
          9.   
          10. /**  
          11.  * get current login user context  
          12.  * @return UserContext  
          13.  */  
          14. protected UserContext getUserContext()   
          15. {   
          16.     Authentication auth = SecurityContextHolder.getContext().getAuthentication();   
          17.     return (UserContext) auth.getPrincipal();   
          18. }   
          <script>render_code();</script>
          這樣在其他的Service和Dao類里可以通過
          代碼
          1. super.getUserContext(), super.getUserInfo()   
          <script>render_code();</script>
          來得到用戶的信息,這也為問題的產生提供了溫床。請看如下代碼:
          代碼
          1. public class SomeServece extends BaseService implements SomeInterFace     
          2. {   
          3.     private UserInfo user = super.getUserInfo();   
          4.        
          5.     public someMethod()   
          6.     {   
          7.        int userID = this.user.getUserID();   
          8.        String userName = this.user.getUserName();   
          9.        //bla bla do something user userID and userNaem   
          10.     }   
          11. }       
          <script>render_code();</script>

           

          這段代碼在單元測試的時候不會用任何問題,但是在多用戶測試的情況下,你會發現任何調用SomeService里someMethod()方法
          的userID和userName都是同一個人,也就是第一個登陸的人的信息。Why?

          其根本原因是Spring的Bean在默認情況下是Singleton的,Bean SomeServece的實例只會生成一份,也就是所SomeServece實例的user
          對象只會被初始化一次,就是第一次登陸人的信息,以后不會變了。所以BaseService想為開發提供方便,卻給開發帶來了風險

          正確的用法應該是這樣的

          代碼
          1. public class SomeServece extends BaseService implements SomeInterFace     
          2. {   
          3.        
          4.        
          5.     public someMethod()   
          6.     {   
          7.        int userID = super.getUserInfo().getUserID();   
          8.        String userName = super.getUserInfo().getUserName();   
          9.        //bla bla do something user userID and userNaem   
          10.     }   
          posted on 2009-04-08 12:12 Sun River 閱讀(755) 評論(0)  編輯  收藏 所屬分類: Spring
          主站蜘蛛池模板: 抚宁县| 高密市| 浦江县| 凉山| 霞浦县| 石台县| 台前县| 山东省| 海南省| 南宁市| 桐庐县| 常山县| 潼关县| 漳州市| 霍林郭勒市| 固原市| 济宁市| 洪泽县| 万州区| 西宁市| 平乐县| 通州区| 宁津县| 剑阁县| 兴海县| 山阴县| 全南县| 潍坊市| 新丰县| 建水县| 德昌县| 吉隆县| 加查县| 普定县| 阳朔县| 锡林浩特市| 农安县| 临潭县| 德兴市| 论坛| 炉霍县|