1. 程式人生 > >spring中的單例和多例中的坑

spring中的單例和多例中的坑

此處僅是問題的簡單描述,並沒有按照規範整理,請大家諒解,這是我在遇到這樣問題時,隨手按照自己的想法記錄下了自己的心得,看著有些亂,不過全是乾貨,希望諒解;

//在springboot 整合rabbitmq下  rabbitTemplate 預設是單例形式
如果僅是傳送佇列和接受佇列訊息 該單例模式就足夠使用了
如果想要 對於 釋出端進行訊息推送確認,那麼單例模式是無法滿足的
如果我們有多個佇列,並需要對每個佇列傳送是否成功的訊息進行確認
這種情況下,如果是單例模式,那麼整個專案中,僅有個一confirm 和 returncallback 實現介面
對於所有的佇列訊息的確認也只能在這一個介面中得到回覆,這樣就很難辨別確認的訊息響應是具體哪個佇列的。

所以這樣的情況下,單例是無法滿足的,因此需要使用多例模式


scope
  prototype 多例模式也會出現一個問題
  
  問題描述
  1  在非指直接請求層  如 server層 ServerImp 使用多例 @Scope("prototype")
    如果在 A 和 B 中分別引用了
    
    A{
      @Autowired
      ServerImp sA;
    }
    
    B{
      @Autowired
      ServerImp sB;
    }
    
  2 此時A和B 都是預設的單例形式作為controller層
    對於A在spring容器啟動的時候,會建立一個A的例項,此時也會建立一個ServerImp的例項 sA
    對於B在spring容器啟動的時候,會建立一個B的例項,此時也會建立一個ServerImp的例項 sB
    
    sA != sB
    但由於a和b僅有一個例項,所以,每次請求使用它們的時候,它們並不會去建立一個新的例項
    那麼此時在a和b中注入的 sA和sB也只是在不同的地方具有不同的例項,但是相對於a和b而言,它們只有一分
    所以,如果在sA和sB中建立了共享變數,那麼這時候就會出現非執行緒安全問題。
    
    
    單例模式
    1  controller server ...等等 在spring容器啟動的時候就會初始化一個單一例項
    
    
  3 scope("prototype") 的時候位置不同,那麼他被初始化和使用的時候也不一樣
   1  使用在controller層的情況下,他是在每次請求到該controller的時候,進行一個例項化,就是建立一個新的controller物件
      在該請求結束後,該controller的例項就會被銷燬,下次再有新的請求進來,就會再次建立一個新的例項
     //使用該註解,標識,在類被例項化後(即呼叫構造方法後),呼叫下面的方法
     @PostConstruct
     public void init(){
        //此處每次有新的請求進來的時候,都會例項化一個新的controller物件
        System.out.println("ProductListController-->init:,this:"+this);
     }
     
  
    
   2  server層使用多例的註解,這個地方會出現很多的坑,這個也是我們需要特別注意的
    首先我們說在預設的單例情況下
    2.1  在controller層 使用@Autowired 來注入一個server層的例項
    2.1  此時spring容器為我們怎麼處理的?
       2.1.1  在建立了一個server單例項後,在引入了該controller的地方,setter到該server的屬性上
         此時如果有3個或者n個controller同時 @Autowired Server 該server,那麼這n個controller同時擁有同一個server物件
       
    此時我們說下多例模式下
   1  controller層是單例
      server層使用多例模式
   2  此時在3個controller中 
       //建立三個controller
       controller_01{
         @Autowired  
         Server server;//  01中的server物件的例項 地址

[email protected]
       }
       controller_02{
         @Autowired  
         Server server  //  02中的server物件的例項 地址 [email protected]
       }
       controller_03{
         @Autowired  
         Server server  //  03中的server物件的例項 地址 [email protected]
       }
       .....
       
       //server層
       @Service
       @Scope("prototype")   
       Server{
       }
       
       我們會發現,在三個controller層注入的server的例項是不一樣的。也就是體現了多例
       
       但是我們需要注意:server的多例是相對於每個不同引入的地方而言的
         其實我們會發現,在spring容器初始化的時候,他會為每一個controller中的server例項化一個物件
         這個例項化物件,就被繫結到了這個controller上了,意思就是(如論你有n多個請求,都請求到同一個controller上
         ,此時這n個請求使用的server物件是同一個。),但是在不同的controller裡的server是不一樣的。
       同理,如果我們的controller是prototype多例的,server也是多例的,這時候的情況和上面也是類似的
       controller多例 是在每次請求的時候建立一個新的例項,
       但是server不一樣,如果在controller裡面,使用@Autowired server進行了注入,該server的例項並不會在每次請求到
       該位置的時候才進行例項化的,仍然是在spring容器初始化的時候就一樣完成了對每個controller的注入
       這裡可能有點繞,下面給出虛擬碼
       //controller——01類  多例
       //在每次新的請求時建立一個新的例項
       @Scope("prototype")
       class controller_01{  
         
         @Autowired
         Server server01  //spring容器初始化的時候為其注入了一個
[email protected]

       }
       
       //controller——02類  多例
       //在每次新的請求時建立一個新的例項
       @Scope("prototype")
       class controller_02{  
         @Autowired
         Server server02;   //spring容器初始化的時候為其注入了一個 [email protected]
       }
       
       //在spring容器初始化的時候,就為存在@Autowired server註解的類注入了一個新的例項
       @Scope("prototype")
       class Server{
       
       }
       
       -------------
       此時有3個請求進入了controller_01中,那麼記憶體中將會建立三個新的例項
       [email protected]
       [email protected]
       [email protected]
       這三個新的例項他們共享server01中的地址[email protected],也就是他們持有同一個server01,
       因為,該server01在spring容器初始話的時候就已經完成了例項化
       
       同理,其他也是這樣
       
       
    探討一個問題
    此時我們就可以利用上面的原理,來解決一些非執行緒安全變數共享問題
    描述:
      有些時候,我們會在server層的類中定義一些私有屬性,這些屬性會被作為該類的全域性變數來使用,而且該屬性是一個動態賦值
    如果向上面那樣,雖然server在被多例後,在不同的controller類下具有不同的例項,但是,對於同一個controller類而言,他們
    持有同一個server物件,也就是該屬性是共享的,隨時可能被另外的請求給修改。
    這時候我們的server中的該屬性是非執行緒安全的。這也是我們平時很少用的情況,嚴格來說也不符合spring的初衷
    如果非要這樣時候怎麼辦,那就不要使用@Autowired 這種方式去獲取server的例項,這種獲取其實也是單例的。
    所以我們要想辦法,在每次請求的時候,都要獲取一個新的server例項,這樣才可以保證變數執行緒安全
    
    @Autowired
    ApplicationContent applicationContent;
    我們可以通過上下文容器在需要的時候主動去獲取,
    Server ser = applicationContent.getBean(Server.class);
    這樣每次獲取到的ser都是一個新的例項。
    
    這樣就解決了多例項的問題
    

相關推薦

spring bean的的使用場景bean注入(不看後悔,一看必懂)

為什麼用單例或者多例?何時用? 之所以用單例,是因為沒必要每個請求都新建一個物件,這樣子既浪費CPU又浪費記憶體; 之所以用多例,是為了防止併發問題;即一個請求改變了物件的狀態,此時物件又處理另一個請求,而之前請求對物件狀態的改變導致了物件對另一個請求做了錯誤的處理;  

spring

此處僅是問題的簡單描述,並沒有按照規範整理,請大家諒解,這是我在遇到這樣問題時,隨手按照自己的想法記錄下了自己的心得,看著有些亂,不過全是乾貨,希望諒解; //在springboot 整合rabbitmq下  rabbitTemplate 預設是單例形式 如果僅是傳送佇

spring詳解。如何在呼叫物件

spring生成物件預設是單例的。通過scope屬性可以更改為多例。 <bean id="user" class="modle.User" scope="prototype"> </bean> 在使用Spring3對控制器Controller進行bean管理時,如果要對控制器是

java的區別

單例 多例 區別 線程 1. 什麽是單例多例:所謂單例就是所有的請求都用一個對象來處理,比如我們常用的service和dao層的對象通常都是單例的,而多例則指每個請求用一個新的對象來處理,比如action; 2. 如何產生單例多例:在通用的SSH中,單例在spring中是默認的,如果要產生多例

java如何運用

單例多例需要搞明白兩個問題: 1. 什麼是單例多例; 2. 如何產生單例多例; 3. 為什麼要用單例多例 4. 什麼時候用單例,什麼時候用多例; 1. 什麼是單例、多例: 所謂單例就是所有的請求都用一個物件來處理,比如我們常用的service和dao

java

你用杯子喝可樂,喝完了不刷,繼續去倒果汁喝,就是單例。 你用杯子喝可樂,直接扔了杯子,換個杯子去倒果汁喝,就是多例。 資料庫連線池就是單例模式,有且僅有一個連線池管理者,管理多個連線池物件。 1. 什麼是單例多例: 所謂單例就是所有的請求都用一個物件來處理,比如我們常用的s

Spring

使用bean的scope屬性來控制單例和多例: <!-- bean 的 scope屬性可以控制單例和多例 singleton是預設值:單例的 ; prototype: 多例的; request: 在web應用中每次請求重新例項化;

spring詳解的實驗,以及如何使用模式

原文:http://www.tuicool.com/articles/RzIvAj spring生成物件預設是單例的。通過scope屬性可以更改為多例。 <bean id="user" class="modle.User" scope="prototype"&

Struts2

text 屬性 用戶修改 出現 兩個 容器 pre min 得到 struts2中action是多例的,即一個session產生一個action如果是單例的話,若出現兩個用戶都修改一個對象的屬性值,則會因為用戶修改時間不同,兩個用戶訪問得到的屬性不一樣,操作得出的結果不一樣

java

單個 static 改變 cpu lazy pack out ont 通過 背景:最近在學習韓老師的筆記時候發現不是很了解單例和多例,於是通過網上查找資料的方式去學習。 設計模式:最佳的實踐,是軟件開發人員在軟件開發過程中面臨一般解決方案,也就是開發的經驗總結。 單例模式(

的區別

單例多例需要搞明白兩個問題: 1. 什麼是單例多例; 2. 如何產生單例多例; 3. 為什麼要用單例多例 4. 什麼時候用單例,什麼時候用多例; 1. 什麼是單例、多例: 所謂單例就是所有的請求都用一個物件來處理,比如我們常用的service和dao層的物件通常都是單

關於struts2 的及執行緒安全的問題

我知道struts 2的Action是多例項的並非單例,也就是每次請求產生一個Action的物件。原因是:struts 2的Action中包含資料,例如你在頁面填寫的資料就會包含在Action的成員變數裡面。如果Action是單例項的話,這些資料在多執行緒的環境下就會相互影

springmvc 開發關於Controller 的情況情況

本案例情況:springmvc+html+url傳遞引數,url直接訪問一個controller來進行頁面分配 在開發的過程中,我們springmvc裡面的controller用的不少,但是需要注意併發的情況。比如我們在做一個介面,所需要的引數是通過url來傳

Spring模式模式

在Spring中,Bean的scope屬性中存在著兩種模式既單例模式(singleton)和多例模式(prototype)。        singleton 單例模式: 物件在整個系統中只有一份,所有的請求都用一個物件來處理,如service和dao層的物件一般是單例的。 

JAVA的實現

這是幾天的學習自己總結下來的一些關於自己對單例和多例的想法。。。。。。(不能與大神的理解相提並論) 單例的第一種 /*懶漢式*/ public class Single { private sta

Spring學習之路--模式模式

在Spring中,bean可以被定義為兩種模式:prototype(多例)和singleton(單例) singleton(單例):只有一個共享的例項存在,所有對這個bean的請求都會返回這個唯一的例項。 prototype(多例):對這個bean的每次請求都會建立一個新

Spring系列之三:SpringBean的構造構造(Maven Idea)

在使用Spring的Ioc容器建立物件會使用到單例構造或多例構造;單例構造:整個程式只有一個物件多例構造:程式中有類例項的多個物件,物件之間互相獨立首先在Test包下面建立一個User類,原始碼如下;package com.lydetails.ssm.Test; public

Spring學習之路——模式模式

在Spring中,bean可以被定義為兩種模式:prototype(多例)和singleton(單例) singleton(單例):只有一個共享的例項存在,所有對這個bean的請求都會返回這個唯一的例項。 prototype(多例):對這個bean的每次請求都會建立一個新的b

線程學習--(六)線程、ThreadLocal

pen single cal final ride args ash public 線程 一、ThreadLocal 使用wait/notify方式實現的線程安全,性能將受到很大影響。解決方案是用空間換時間,不用鎖也能實現線程安全。 來看一個小例子,在線程內的set、get

spring自動註入是還是例如何註入

struts1 contex resolv inject interface struts2 ans 我們 instant 單例多例需要搞明白這些問題: 1. 什麽是單例多例; 2. 如何產生單例多例; 3. 為什麽要用單例多例 4.