Singleton 设计模式与 Spring 容器中的 Singleton bean

发布于 2024-08-29 01:13:31 字数 156 浏览 6 评论 0原文

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

如果我无法解释我真正想问的内容,请耐心等待。

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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

老旧海报 2024-09-05 01:13:31

Spring 中的单例 bean 和单例模式有很大不同。单例模式表示每个类加载器将创建一个且仅一个特定类的实例。

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

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

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

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.

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.

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

<bean id=".." class=".." scope="prototype" />
谎言月老 2024-09-05 01:13:31

我发现“每个容器每个豆子”很难理解。我会说“容器中每个 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引用的相同的bean。如果我尝试使用 id7 获取它,将从 Sample 类创建另一个 bean,每次使用 id7 引用该 bean 时都会缓存并返回相同的 bean。

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

I find "per container per bean" difficult to apprehend. I would say "one bean per bean id in a container".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="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.

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

岁月静好 2024-09-05 01:13:31

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

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

或者,我们可以在 bean 定义中使用工厂方法属性,如下所示

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

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.

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

    <bean id="exampleBean" class="example.Singleton"  factory-method="getInstance"/>
何止钟意 2024-09-05 01:13:31

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

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

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

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

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

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.

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.

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.

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.

拔了角的鹿 2024-09-05 01:13:31

Spring 中的单例范围意味着该 bean 只会被 Spring 实例化一次。与原型作用域(每次新实例)、请求作用域(每个请求一次)、会话作用域(每个 HTTP 会话一次)相反。

从技术上讲,单例范围与单例设计模式无关。您不必将 bean 实现为单例,即可将它们放入单例范围中。

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).

Singleton scope has technically nothing 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.

只有影子陪我不离不弃 2024-09-05 01:13:31

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

例如,如果我有一个名为“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>

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

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

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

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.

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

<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:-

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

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.

狂之美人 2024-09-05 01:13:31

至少到目前为止,所有答案都集中在解释设计模式和 Spring 单例之间的区别,而没有解决您的实际问题:应该使用 Singleton 设计模式还是 Spring 单例 bean?什么更好?

在我回答之前,我先声明一下,两者都可以做。您可以将 bean 实现为 Singleton 设计模式,并使用 Spring 将其作为 Spring singleton bean 注入到客户端类中。

现在,问题的答案很简单:不要使用单例设计模式!
使用 Spring 的单例 bean 实现为具有公共构造函数的类。
为什么?因为单例设计模式被认为是反模式。主要是因为它使测试变得复杂。 (如果您不使用 Spring 来注入它,那么所有使用单例的类现在都与它紧密绑定),并且您无法替换或扩展它。人们可以通过谷歌搜索“Singleton anti-pattern”来获取更多信息,例如 Singleton anti- 使用 Spring 单例

是一种可行的方法(使用单例 bean 实现不是作为单例设计模式,而是使用公共构造函数),以便可以轻松测试 Spring 单例 bean,并且使用它的类是与其紧密耦合,而是 Spring 将单例(作为接口)注入到所有需要它的 bean 中,并且单例 bean 可以随时用另一个实现替换,而不会影响使用它的客户端类。

All the answers, so far at least, concentrate on explaining the difference between the design pattern and Spring singleton and do not address your actual question: Should a Singleton design pattern be used or a Spring singleton bean? what is better?

Before I answer let me just state that you can do both. You can implement the bean as a Singleton design pattern and use Spring to inject it into the client classes as a Spring singleton bean.

Now, the answer to the question is simple: Do not use the Singleton design pattern!
Use Spring's singleton bean implemented as a class with public constructor.
Why? Because the Singleton design pattern is considered an anti-pattern. Mostly because it complicates testing. (And if you don't use Spring to inject it then all classes that use the singleton are now tightly bound to it), and you can't replace or extend it. One can google "Singleton anti-pattern" to get more info on this, e.g. Singleton anti-pattern

Using Spring singleton is the way to go (with a the singleton bean implemented NOT as a Singleton design pattern, but rather with a public constructor) so that the Spring singleton bean can easily be tested and classes that use it are not tightly coupled to it, but rather, Spring injects the singleton (as an interface) into all the beans that need it, and the singleton bean can be replaced any time with another implementation without affecting the client classes that use it.

南风起 2024-09-05 01:13:31

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

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

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

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.

那片花海 2024-09-05 01:13:31

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

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.

泪眸﹌ 2024-09-05 01:13:31

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

"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.

<逆流佳人身旁 2024-09-05 01:13:31

例如:“每个容器每个豆子”。

        <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 单例:

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());
    }

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());
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文