Java 单例设计模式与 Spring 容器中的单例 bean

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2637864/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 10:12:15  来源:igfitidea点击:

Singleton design pattern vs Singleton beans in Spring container

javaspringsingletoncontainers

提问by Peeyush

As we all know we have beans as singleton by default in Spring container and if we have a web application based on Spring framework then in that case do we really need to implement Singleton design pattern to hold global data rather than just creating a bean through spring.

众所周知,我们在 Spring 容器中默认将 bean 作为单例,如果我们有一个基于 Spring 框架的 Web 应用程序,那么在这种情况下,我们是否真的需要实现单例设计模式来保存全局数据,而不仅仅是通过 spring 创建一个 bean .

Please bear with me if I'm not able to explain what I actually meant to ask.

如果我无法解释我真正想问的是什么,请耐心等待。

回答by lexicore

Singleton scope in Spring means that this bean will be instantiated only once by Spring. In contrast to the prototype scope (new instance each time), request scope (once per request), session scope (once per HTTP session).

Spring 中的单例作用域意味着这个 bean 只会被 Spring 实例化一次。对比原型范围(每次都有新实例)、请求范围(每个请求一次)、会话范围(每个 HTTP 会话一次)。

Singleton scope has technically noting to do with the singleton design pattern. You don't have to implement your beans as singletons for them to be put in the singleton scope.

单例范围在技术上与单例设计模式有关。您不必将 bean 实现为单例,以便将它们放入单例范围。

回答by user184794

A singleton bean in Spring and the singleton pattern are quite different. Singleton pattern says that one and only one instance of a particular class will ever be created per classloader.

Spring 中的单例 bean 和单例模式完全不同。单例模式表示,每个类加载器将永远创建一个且只有一个特定类的实例。

The scope of a Spring singleton is described as "per container per bean". It is the scope of bean definition to a single object instance per Spring IoC container. The default scope in Spring is Singleton.

Spring 单例的范围被描述为“每个容器每个 bean”。它是 bean 定义的范围到每个 Spring IoC 容器的单个对象实例。Spring 中的默认范围是 Singleton。

Even though the default scope is singleton, you can change the scope of bean by specifying the scope attribute of <bean ../>element.

即使默认范围是单例,您也可以通过指定<bean ../>元素的 scope 属性来更改 bean 的范围。

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

回答by lwpro2

"singleton" in spring is using bean factory get instance, then cache it; which singleton design pattern is strictly, the instance can only be retrieved from static get method, and the object can never be publicly instantiated.

spring中的“singleton”是使用bean factory获取实例,然后缓存它;哪个单例设计模式是严格的,实例只能从静态get方法中获取,并且对象永远不能被公开实例化。

回答by Vasanth

Singleton scope in spring means single instance in a Spring context ..
Spring container merely returns the same instance again and again for subsequent calls to get the bean.


And spring doesn't bother if the class of the bean is coded as singleton or not , in fact if the class is coded as singleton whose constructor as private, Spring use BeanUtils.instantiateClass (javadoc here) to set the constructor to accessible and invoke it.

spring 中的单例范围意味着 Spring 上下文中的单个实例..
Spring 容器只是一次又一次地返回相同的实例,以便后续调用获取 bean。


如果 bean 的类是否编码为单例,spring 不会在意,事实上,如果类编码为单例,其构造函数为私有,则 Spring 使用 BeanUtils.instantiateClass(此处为javadoc )将构造函数设置为可访问并调用它。

Alternatively, we can use a factory-method attribute in bean definition like this

或者,我们可以像这样在 bean 定义中使用 factory-method 属性

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

回答by JavaMave

Singleton beans in Spring and classes based on Singleton design pattern are quite different.

Spring 中的单例 bean 和基于单例设计模式的类有很大不同。

Singleton pattern ensures that one and only one instance of a particular class will ever be created per classloader where as the scope of a Spring singleton bean is described as 'per container per bean'. Singleton scope in Spring means that this bean will be instantiated only once by Spring. Spring container merely returns the same instance again and again for subsequent calls to get the bean.

单例模式确保每个类加载器只创建一个特定类的一个实例,其中 Spring 单例 bean 的范围被描述为“每个容器每个 bean”。Spring 中的单例作用域意味着这个 bean 只会被 Spring 实例化一次。Spring 容器只是一次又一次地返回相同的实例,以便后续调用获取 bean。

回答by inor

Let's take the simplest example: you have an application and you just use the default classloader. You have a class which, for whatever reason, you decide that it should not have more than one instance in the application. (Think of a scenario where several people work on pieces of the application).

让我们举一个最简单的例子:你有一个应用程序,你只使用默认的类加载器。您有一个类,无论出于何种原因,您决定它在应用程序中不应有多个实例。(想想几个人在应用程序的各个部分工作的场景)。

If you are not using the Spring framework, the Singleton pattern ensures that there will not be more than one instance of a class in your application. That is because you cannot instantiate instances of the class by doing 'new' because the constructor is private. The only way to get an instance of the class is to call some static method of the class (usually called 'getInstance') which always returns the same instance.

如果您没有使用 Spring 框架,单例模式可确保您的应用程序中不会有多个类的实例。那是因为您不能通过执行 'new' 来实例化类的实例,因为构造函数是私有的。获取类实例的唯一方法是调用类的一些静态方法(通常称为“getInstance”),它总是返回相同的实例。

Saying that you are using the Spring framework in your application, just means that in addition to the regular ways of obtaining an instance of the class (new or static methods that return an instance of the class), you can also ask Spring to get you an instance of that class and Spring will ensure that whenever you ask it for an instance of that class it will always return the same instance, even if you didn't write the class using the Singleton pattern. In other words, even if the class has a public constructor, if you always ask Spring for an instance of that class, Spring will only call that constructor once during the life of your application.

说你在你的应用程序中使用的是Spring框架,只是意味着除了常规的获取类实例的方式(返回类的实例的新方法或静态方法)之外,你还可以要求Spring获取你该类的实例和 Spring 将确保每当您向它请求该类的实例时,它总是返回相同的实例,即使您没有使用单例模式编写该类。换句话说,即使该类有一个公共构造函数,如果你总是向 Spring 请求该类的一个实例,Spring 在你的应用程序生命周期中只会调用该构造函数一次。

Normally if you are using Spring, you should only use Spring to create instances, and you can have a public constructor for the class. But if your constructor is not private you are not really preventing anyone from creating new instances of the class directly, by bypassing Spring.

通常,如果您使用 Spring,您应该只使用 Spring 创建实例,并且您可以为该类创建一个公共构造函数。但是如果你的构造函数不是私有的,你并没有真正阻止任何人通过绕过 Spring 直接创建类的新实例。

If you truly want a single instance of the class, even if you use Spring in your application and define the class in Spring to be a singleton, the only way to ensure that is also implement the class using the Singleton pattern. That ensures that there will be a single instance, whether people use Spring to get an instance or bypass Spring.

如果您真的想要该类的单个实例,即使您在应用程序中使用 Spring 并将 Spring 中的类定义为单例,确保也是使用单例模式实现该类的唯一方法。这确保了将有一个实例,无论人们使用 Spring 获取实例还是绕过 Spring。

回答by Hariprasad

EX: "per container per 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());
    }

回答by Sibaprasad Sahoo

Spring singleton bean is described as 'per container per bean'. Singleton scope in Spring means that same object at same memory location will be returned to same bean id. If one creates multiple beans of different ids of the same class then container will return different objects to different ids. This is like a key value mapping where key is bean id and value is the bean object in one spring container. Where as Singleton pattern ensures that one and only one instance of a particular class will ever be created per classloader.

Spring 单例 bean 被描述为“每个容器每个 bean”。Spring 中的单例范围意味着相同内存位置的相同对象将返回到相同的 bean id。如果一个人创建了同一个类的不同 id 的多个 bean,那么容器将返回不同的对象到不同的 id。这就像一个键值映射,其中键是 bean id,值是一个 spring 容器中的 bean 对象。单例模式确保每个类加载器只创建一个特定类的一个实例。

回答by Dexter

I find "per container per bean" difficult to apprehend. I would say "one bean per bean id".Lets have an example to understand it. We have a bean class Sample. I have defined two beans from this class in bean definition, like:

我发现“每个容器每个豆子”很难理解。我会说“每个 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>

So when ever I try to get the bean with id "id1",the spring container will create one bean, cache it and return same bean where ever refered with id1. If I try to get it with id7, another bean will be created from Sample class, same will be cached and returned each time you referred that with id7.

因此,当我尝试获取 id 为“id1”的 bean 时,spring 容器将创建一个 bean,缓存它并返回与 id1 引用的相同 bean。如果我尝试使用 id7 获取它,则会从 Sample 类创建另一个 bean,每次使用 id7 引用它时,都会缓存并返回相同的 bean。

This is unlikely with Singleton pattern. In Singlton pattern one object per class loader is created always. However in Spring, making the scope as Singleton does not restrict the container from creating many instances from that class. It just restricts new object creation for the same ID again, returning previously created object when an object is requested for the same id. Reference

单例模式不太可能出现这种情况。在 Singlton 模式中,每个类加载器总是创建一个对象。但是在 Spring 中,将作用域设为 Singleton 并不会限制容器从该类创建许多实例。它只是再次限制为同一 ID 创建新对象,当为相同 id 请求对象时返回先前创建的对象参考

回答by hhhakki

There is a very fundamental difference between the two. In case of Singleton design pattern, only one instance of a class will be created per classLoader while that is not the case with Spring singleton as in the later one shared bean instance for the given id per IoC container is created.

两者之间有非常根本的区别。在单例设计模式的情况下,每个 classLoader 只会创建一个类的实例,而 Spring 单例则不是这种情况,因为稍后会为每个 IoC 容器创建一个给定 id 的共享 bean 实例。

For example, if I have a class with the name "SpringTest" and my XML file looks something like this :-

例如,如果我有一个名为“SpringTest”的类,而我的 XML 文件如下所示:-

<bean id="test1" class="com.SpringTest" scope="singleton">
        --some properties here
</bean>    
<bean id="test2" class="com.SpringTest" scope="singleton">
        --some properties here   
</bean>

So now in the main class if you will check the reference of the above two it will return false as according to Spring documentation:-

所以现在在主类中,如果您将检查上述两个的引用,它将根据 Spring 文档返回 false:-

When a bean is a singleton, only one shared instance of the bean will be managed, and all requests for beans with an id or ids matching that bean definition will result in that one specific bean instance being returned by the Spring container

当 bean 是单例时,只会管理该 bean 的一个共享实例,并且所有对具有与该 bean 定义匹配的 id 或 ids 的 bean 的请求将导致 Spring 容器返回该特定 bean 实例

So as in our case, the classes are the same but the id's that we have provided are different hence resulting in two different instances being created.

所以在我们的例子中,类是相同的,但我们提供的 id 是不同的,因此导致创建了两个不同的实例。