2010-04-14 103 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