2010-04-14 86 views
74

衆所周知,Spring容器默認情況下bean有singleton,如果我們有一個基於Spring框架的Web應用程序,那麼在這種情況下,我們是否真的需要實現Singleton設計模式掌握全球數據,而不是僅僅通過春天創建一個bean。Singleton設計模式vs Spring中的Singleton bean容器

如果我無法解釋我真正想要問什麼,請耐心等待。

回答

9

Spring中的單例範圍意味着這個bean將僅在Spring中實例化一次。與原型範圍(每次新實例)相比,請求範圍(每個請求一次),會話範圍(每個HTTP會話一次)。

單身職責範圍在技術上與單身設計模式有關。您不必將您的bean實現爲單例,以便將它們放入單例作用域中。

+0

糾正我,如果我錯了,所以根據你,如果我需要實現任何對象作爲單身人士,所以不需要實現單身模式。使用Spring創建該bean將起作用。我現在有點困惑,我的理解與Spring框架中的Singleton設計模式和Singleton範圍有關。 – Peeyush 2010-04-14 17:08:52

+1

Spring不會強制您使用Singleton模式。 – lexicore 2010-04-14 17:19:20

46

Spring中的singleton bean和singleton模式有很大不同。 Singleton模式表示,每個類加載器都會創建一個特定類的唯一實例。

Spring單例的範圍被描述爲「每個bean每個容器」。這是每個Spring IoC容器對單個對象實例的bean定義範圍。 Spring中的默認範圍是Singleton。

儘管默認範圍是單例,但您可以通過指定<bean ../>元素的scope屬性來更改bean的範圍。

<bean id=".." class=".." scope="prototype" /> 
+7

@ user184794:每個bean每個容器,這意味着在spring容器中只有一個類加載器。如果在spring容器中有兩個或多個類加載器,那麼每個類加載器都有自己的實例。它是否意味着「每個bean每個類加載器的每個容器」。請澄清! – 2011-07-28 10:59:23

+4

我認爲這意味着Spring容器將使用它擁有的一個類加載器。你在Spring的機制之外做了什麼並不相關,也就是說,你可以創建自己的類加載器並根據需要創建一個類的實例,但是如果你通過Spring容器,它將不會創建多個實例 – inor 2014-05-08 08:36:32

+0

然後他們並不像你說的那樣「非常不同」。唯一的區別是範圍 - Spring容器verses classloader – 2017-10-10 18:00:13

1

「singleton」在spring中使用bean factory獲取實例,然後緩存它;哪個單例設計模式是嚴格的,實例只能從靜態獲取方法中獲取,並且該對象永遠不能公開實例化。

25

Spring中的單例範圍意味着Spring環境中的單例。
Spring容器只是一次又一次地返回相同的實例,以便後續調用獲取bean。


如果bean的類被編碼爲singleton或不是,實際上如果類被編碼爲singleton的構造函數爲private,那麼Spring使用BeanUtils.instantiateClass(javadoc here)來設置構造函數訪問和調用它。

或者,我們可以在bean定義工廠方法屬性像在春天這個

<bean id="exampleBean" class="example.Singleton" factory-method="getInstance"/> 
+1

你確定你需要factory-method屬性嗎?我很確定Spring知道如何獲得一個實例,即使構造函數是私有的(可能會嘗試調用getInstance) – inor 2014-07-28 05:32:22

+0

關於Spring如何調用私有構造函數[here]的相關討論(http://stackoverflow.com/a/7254617/ 2841265) – 2015-09-18 07:08:53

2

辛格爾頓豆類和類基於Singleton設計模式有很大的不同。

單例模式確保每個類加載器都會創建一個特定類的唯一實例,因爲Spring單例bean的範圍被描述爲「每個容器每個bean」。 Spring中的單例範圍意味着這個bean將僅在Spring中實例化一次。 Spring容器只是一次又一次地返回相同的實例,以便後續調用來獲取bean。

+10

你是'java特立獨行',對不對?這會讓你的陳述「在...發現一個很好的解釋和例子」,這是一個不誠實的企圖隱瞞你正在鏈接到你自己的網站。無論如何,你的鏈接對於答案似乎並不重要。我將其刪除,以避免將答案作爲垃圾郵件刪除。在發佈更多鏈接到您的網站之前,請閱讀自我推銷的常見問題解答。還請注意,將您的網站鏈接放入您的個人資料中相當好。 – 2012-11-27 18:46:41

15

讓我們舉一個最簡單的例子:你有一個應用程序,你只需要使用默認的類加載器。你有一個類,無論出於何種原因,你決定它在應用程序中不應該有多個實例。 (想想幾個人在應用程序中工作的場景)。

如果您不使用Spring框架,Singleton模式可確保應用程序中不會有多於一個類的實例。這是因爲你不能通過執行'new'來實例化類的實例,因爲構造函數是私有的。獲得該類實例的唯一方法是調用該類的一些靜態方法(通常稱爲「getInstance」),該方法始終返回相同的實例。

說您在您的應用程序中使用Spring框架,只是意味着除了獲取類的實例(返回類的實例的新方法或靜態方法)的常規方法之外,您還可以詢問Spring爲你提供該類的一個實例,Spring將確保無論何時你要求它爲該類的一個實例,它總是會返回同一個實例,即使你沒有使用Singleton模式編寫該類。換句話說,即使這個類有一個公共構造函數,如果你總是向Spring請求這個類的一個實例,那麼Spring在你的應用程序的整個生命週期中只會調用這個構造函數。

通常情況下,如果你使用的是Spring,你應該只使用Spring來創建實例,並且你可以爲這個類創建一個公共構造函數。但是如果你的構造函數不是私有的,那麼你並不真正阻止任何人直接創建類的新實例,因爲它繞過了Spring。

如果您確實需要該類的單個實例,即使在您的應用程序中使用Spring並將Spring中的類定義爲單例,唯一的方法也是確保使用Singleton模式實現該類。這確保了會有單個實例,無論人們使用Spring來獲取實例還是繞過Spring。

1

EX:「每個容器每個bean」。

 <bean id="myBean" class="com.spring4hibernate4.TestBean"> 
      <constructor-arg name="i" value="1"></constructor-arg> 
      <property name="name" value="1-name"></property> 
     </bean> 

     <bean id="testBean" class="com.spring4hibernate4.TestBean"> 
      <constructor-arg name="i" value="10"></constructor-arg> 
      <property name="name" value="10-name"></property> 
     </bean> 
    </beans> 



    public class Test { 

     @SuppressWarnings("resource") 
     public static void main(String[] args) { 
      ApplicationContext ac = new ClassPathXmlApplicationContext("ws.xml"); 
      TestBean teatBean = (TestBean) ac.getBean("testBean"); 
      TestBean myBean1 = (TestBean) ac.getBean("myBean"); 
      System.out.println("a : " + teatBean.test + " : " + teatBean.getName()); 
      teatBean.setName("a TEST BEAN 1"); 
      System.out.println("uPdate : " + teatBean.test + " : " + teatBean.getName()); 
      System.out.println("a1 : " + myBean1.test + " : " + myBean1.getName()); 
      myBean1.setName(" a1 TEST BEAN 10"); 
      System.out.println("a1 update : " + teatBean.test + " : " + myBean1.getName()); 
     } 
    } 

public class TestBean { 
    public int test = 0; 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    private String name = "default"; 

    public TestBean(int i) { 
     test += i; 
    } 
} 

JAVA SINGLETON:

public class Singleton { 
    private static Singleton singleton = new Singleton(); 
    private int i = 0; 

    private Singleton() { 
    } 

    public static Singleton returnSingleton() { 

     return singleton; 
    } 

    public void increment() { 
     i++; 
    } 

    public int getInt() { 
     return i; 
    } 
} 

public static void main(String[] args) { 
     System.out.println("Test"); 

     Singleton sin1 = Singleton.returnSingleton(); 
     sin1.increment(); 
     System.out.println(sin1.getInt()); 
     Singleton sin2 = Singleton.returnSingleton(); 
     System.out.println("Test"); 
     sin1.increment(); 
     System.out.println(sin1.getInt()); 
    } 
+0

\t \t <構造精氨酸名稱= 「i」 的值= 「1」> \t \t <屬性名= 「名稱」 的值=」 1名 「> \t \t \t \t <構造精氨酸名稱=」 i」的值= 「10」> \t \t \t – Hariprasad 2015-09-16 10:17:10

0

彈簧單豆描述 '每容器每豆' 作爲。 Spring中的Singleton範圍意味着同一個內存位置的同一個對象將被返回到相同的bean ID。如果創建了多個相同類的不同id的bean,容器將不同的對象返回給不同的id。這就像一個鍵值映射,其中key是bean id,value是一個spring容器中的bean對象。 Singleton模式確保每個類加載器創建一個特定類的唯一實例。

1

我發現「per container per bean」很難理解。我會說「每個bean id一個bean」。讓我們用一個例子來理解它。我們有一個Bean類Sample。我從這個類的bean定義兩個bean,如:

<bean id="id1" class="com.example.Sample" scope="singleton"> 
     <property name="name" value="James Bond 001"/>  
</bean>  
<bean id="id7" class="com.example.Sample" scope="singleton"> 
     <property name="name" value="James Bond 007"/>  
</bean> 

所以,當過我嘗試獲取ID爲「ID1」的bean時,Spring容器將創建一個豆,緩存並返回同一個bean曾經引用過id1的地方。如果我嘗試使用id7來獲取它,則將從Sample類創建另一個bean,並且每次使用id7引用時都會緩存並返回。

這對單例模式來說不太可能。在Singlton模式中,每個類加載器總是創建一個對象。但在春天,許多對象正在爲同一個班級創建。然而,在Spring中,作爲Singleton的作用域爲相同的ID返回相同的對象。 Reference