Java spring默认范围是单例吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31629993/
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-11 11:20:01  来源:igfitidea点击:

Is spring default scope singleton or not?

javaspringdependency-injectionsingletonspring-ioc

提问by Raj

Could you please explain why Spring is creating two objects for the configuration of beans shown below, since by default spring default scope is singleton?

您能否解释一下为什么 Spring 为如下所示的 beans 配置创建两个对象,因为默认情况下 spring 默认范围是单例?

The Spring configuration is here:

Spring配置在这里:

<bean id="customer" class="jp.ne.goo.beans.Customer"> 
    <property name="custno" value="100"></property>
    <property name="custName" value="rajasekhar"> </property>
</bean>
<bean id="customer2" class="jp.ne.goo.beans.Customer"> 
    <property name="custno" value="200"></property> 
    <property name="custName" value="siva"></property> 
</bean>

回答by Anupama Rao

Spring default scope is singleton and it will create one object for all instances unless you explicitly specify the scope to be prototype. You have not posted spring configuration. Please post it, it will give a better idea.

Spring 默认范围是单例,除非您明确指定范围为原型,否则它将为所有实例创建一个对象。您还没有发布弹簧配置。请发布它,它会提供更好的主意。

回答by Nathan Hughes

Spring's default scope issingleton. It's just that your idea of what it means to be a singleton doesn't match how Spring defines singletons.

Spring 的默认范围单例。只是您对单身意味着什么的想法与 Spring 定义单身的方式不符。

If you tell Spring to make two separate beans with different ids and the same class, then you get two separate beans, each with singleton scope. All singleton scope means is that when you reference something with the same id, you get the same bean instance back.

如果您告诉 Spring 使用不同的 id 和相同的类创建两个单独的 bean,那么您将得到两个单独的 bean,每个 bean 都有单例作用域。所有的单例作用域都意味着当你引用具有相同 id 的东西时,你会得到相同的 bean 实例。

Here is how the Spring documentation defines singleton scope:

以下是Spring 文档如何定义单例范围

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

仅管理单例 bean 的一个共享实例,并且对具有与该 bean 定义匹配的一个或多个 id 的 bean 的所有请求都会导致 Spring 容器返回一个特定的 bean 实例。

Singleton scope means using the same id retrieves the same bean, that is all. Testing that no two ids referenced the same class would get in the way of using maps as beans, and would be complicated by proxying things with BeanFactories. For Spring to police this would involve a lot of work for little benefit, instead it trusts the users to know what they're doing.

单例范围意味着使用相同的 id 检索相同的 bean,仅此而已。测试没有两个 id 引用同一个类会妨碍将映射用作 bean,并且会因使用 BeanFactories 代理而变得复杂。对于 Spring 进行监管,这将涉及大量工作,但收益甚微,相反,它相信用户知道他们在做什么。

The way to define two names for the same bean is to use an alias:

为同一个 bean 定义两个名称的方法是使用别名

In a bean definition itself, you can supply more than one name for the bean, by using a combination of up to one name specified by the id attribute, and any number of other names in the name attribute. These names can be equivalent aliases to the same bean, and are useful for some situations, such as allowing each component in an application to refer to a common dependency by using a bean name that is specific to that component itself.

Specifying all aliases where the bean is actually defined is not always adequate, however. It is sometimes desirable to introduce an alias for a bean that is defined elsewhere. This is commonly the case in large systems where configuration is split amongst each subsystem, each subsystem having its own set of object definitions. In XML-based configuration metadata, you can use the element to accomplish this.

在 bean 定义本身中,您可以通过使用 id 属性指定的最多一个名称和 name 属性中任意数量的其他名称的组合,为 bean 提供多个名称。这些名称可以是同一个 bean 的等效别名,并且在某些情况下很有用,例如允许应用程序中的每个组件通过使用特定于该组件本身的 bean 名称来引用公共依赖项。

然而,在实际定义 bean 的地方指定所有别名并不总是足够的。有时需要为在别处定义的 bean 引入别名。这在大型系统中很常见,其中配置在每个子系统之间拆分,每个子系统都有自己的一组对象定义。在基于 XML 的配置元数据中,您可以使用元素来完成此操作。

So if you add a name in the bean configuration:

因此,如果您在 bean 配置中添加一个名称:

<bean id="customer" name="customer2" 
    class="jp.ne.goo.beans.Customer">
</bean>

or create an alias for a bean defined elsewhere:

或为别处定义的 bean 创建别名:

<alias name="customer" alias="customer2"/>

then "customer" and "customer2" will refer to the same bean instance.

那么“customer”和“customer2”将引用同一个bean实例。

回答by Gab

You're confusing two different concepts.

你混淆了两个不同的概念。

The word singleton in spring is used for a bean scope, meaning that the bean will be created only once for the whole application.

spring 中的单例一词用于 bean 范围,这意味着该 bean 将为整个应用程序只创建一次。

Singleton usual meaning refers to the GOF pattern. It is an object oriented pattern guarantying that only one instance of a class will exists (at least in the scope of the classLoader).

Singleton 通常的意思是指 GOF 模式。它是一种面向对象的模式,保证一个类只存在一个实例(至少在 classLoader 的范围内)。

回答by Berrigan

You are declaring two beans of the same class. That isn't the same.

您正在声明同一类的两个 bean。那不一样。

@Component("springTestClass")
public class SpringTestClass{
     private int randomNumber = 0;
     public SpringTestClass(){
       randomNumber = new Random().nextInt(2000);
     }

     public int getRandomNumber(){
       return this.randomNumber;
     }

}

And try to access this bean in two places the number will be the same. But what you have done was creating two separate beans.

并尝试在两个地方访问这个 bean 的数量将是相同的。但是您所做的是创建两个独立的 bean。

If you want to check if this works try:

如果您想检查这是否有效,请尝试:

public class Main{
   public static void main(String[] args){
     ApplicationContext ctx = ....;
     SpringTestClass testObject1 = (SpringTestClass)ctx.getBean("springTestClass");
     SpringTestClass testObject2 = (SpringTestClass)ctx.getBean("springTestClass");

    System.out.println(testObject1.getRandomNumber() == testObject2.getRandomNumber());
   }
}

This code should return true if it is same instance; But in SpringTestClass you can add @Scope("prototype") annotation. The output will be false

如果是同一个实例,此代码应返回 true;但是在 SpringTestClass 中,您可以添加 @Scope("prototype") 注释。输出将是假的

回答by ryoung10

Like others have mentioned, two beans should be created from the code you posted. Singletons are defined as follows (from the Spring documentation: Singleton Scope)

就像其他人提到的那样,应该从您发布的代码中创建两个 bean。单例定义如下(来自 Spring 文档:Singleton Scope

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

仅管理单例 bean 的一个共享实例,并且对具有与该 bean 定义匹配的一个或多个 id 的 bean 的所有请求都会导致 Spring 容器返回一个特定的 bean 实例。

To add clarity to this, the meaning behind "shared instance" is explained in the paragraph that follows the one above:

为了更清楚地说明这一点,“共享实例”背后的含义在上述段落之后的段落中进行了解释:

all subsequent requests and references for that named bean return the cached object

该命名 bean 的所有后续请求和引用都返回缓存的对象

When a singleton bean is created, only one bean object is instantiated and cached. This refers only to the bean, not to whatever class the bean may be an instance of. For example,

创建单例 bean 时,仅实例化和缓存一个 bean 对象。这仅指bean,而不是bean 可能是其实例的任何类。例如,

<bean id="myBean" class="myPackage.myClass" />

<bean id="myOtherBean1 class="myPackage.myOtherClass1">
    <property name="beanReference1" ref="myBean" />
</bean>
<bean id="myOtherBean2 class="myPackage.myOtherClass2">
    <property name="beanReference2" ref="myBean" />
</bean>

In this made up configuration, "myOtherBean1" and "myOtherBean2" have references to the same "myBean" bean therefore the same "myPackage.myClass" instance. If you changed the code to add a second "myPackage.myClass" bean, it would be distinct from "myBean".

在这个组合配置中,“myOtherBean1”和“myOtherBean2”引用了同一个“myBean”bean,因此是同一个“myPackage.myClass”实例。如果您更改代码以添加第二个“myPackage.myClass”bean,它将与“myBean”不同。

To fully understand this, also refer to the other Spring scope: the prototype. From the Spring documentation for Prototype Scope:

要完全理解这一点,还可以参考另一个 Spring 范围:原型。来自Prototype Scope的 Spring 文档:

The non-singleton, prototype scope of bean deployment results in the creation of a new bean instance every time a request for that specific bean is made.

bean 部署的非单一原型范围导致每次对特定 bean 发出请求时都会创建一个新 bean 实例。

This means that if we were to use the same Spring XML as above, "myOtherBean1" and "myOtherBean2" would each receive their own distinct copies of "myBean" which is still just an instance of "myPackage.myClass".

这意味着,如果我们使用与上面相同的 Spring XML,“myOtherBean1”和“myOtherBean2”将各自收到他们自己不同的“myBean”副本,它仍然只是“myPackage.myClass”的一个实例。

回答by Adam Ostro?lík

The following example shows a @Bean annotated method being called twice:

以下示例显示了一个被 @Bean 注释的方法被调用两次:

@Configuration
public class AppConfig {

    @Bean
    public ClientService clientService1() {
        ClientServiceImpl clientService = new ClientServiceImpl();
        clientService.setClientDao(clientDao());
        return clientService;
    }

    @Bean
    public ClientService clientService2() {
        ClientServiceImpl clientService = new ClientServiceImpl();
        clientService.setClientDao(clientDao());
        return clientService;
    }

    @Bean
    public ClientDao clientDao() {
        return new ClientDaoImpl();
    }

}

clientDao() has been called once in clientService1() and once in clientService2(). Since this method creates a new instance of ClientDaoImpl and returns it, you would normally expect having 2 instances (one for each service). That definitely would be problematic: in Spring, instantiated beans have a singleton scope by default. This is where the magic comes in: All @Configuration classes are subclassed at startup-time with CGLIB. In the subclass, the child method checks the container first for any cached (scoped) beans before it calls the parent method and creates a new instance. Note that as of Spring 3.2, it is no longer necessary to add CGLIB to your classpath because CGLIB classes have been repackaged under org.springframework.cglib and included directly within the spring-core JAR.

clientDao() 已在 clientService1() 和 clientService2() 中调用一次。由于此方法会创建一个 ClientDaoImpl 的新实例并返回它,因此您通常会期望有 2 个实例(每个服务一个)。这肯定会有问题:在 Spring 中,默认情况下实例化的 bean 具有单例作用域。这就是神奇之处:所有@Configuration 类在启动时使用 CGLIB 进行子类化。在子类中,子方法在调用父方法并创建新实例之前,首先检查容器中是否有任何缓存的(作用域)bean。请注意,从 Spring 3.2 开始,不再需要将 CGLIB 添加到您的类路径中,因为 CGLIB 类已在 org.springframework.cglib 下重新打包并直接包含在 spring-core JAR 中。

回答by Pritam

In SPring Singleton referes to One bean per Spring container where as in Java Singleton refers to one object per class loader.

在 SPring 中单例是指每个 Spring 容器一个 bean,而在 Java 中单例是指每个类加载器一个对象。

So Spring singleton is not same as java singleton. Don't get confused between these two.

所以Spring单例与java单例不同。不要混淆这两者。

回答by gopal jha

Spring Singleton Bean Does not work like Java Singleton.

Spring Singleton Bean 不像 Java Singleton 那样工作。

If we write

如果我们写

ApplicationContext ctx = new ClassPathXmlApplicationContext("MyConfig.xml");
        Customer obj1= (Customer) ctx.getBean("customer");
        Customer obj2 = (Customer) ctx.getBean("customer2");
        System.out.println(obj1 == obj2);
        System.out.println(obj1+ "::" + obj2);

If we see the output it will return 2 different Instance. According to Spring Docs Bean is singleton only one shared Instance will be managed, and all request beans with an ID or ID matching that bean definition. Here 2 different ID is available.

如果我们看到输出,它将返回 2 个不同的实例。根据 Spring Docs Bean 是单例的,只有一个共享实例将被管理,所有请求 bean 的 ID 或 ID 与该 bean 定义匹配。这里有 2 个不同的 ID 可用。

Spring container as managing Key value pair, Key as ID/Name and value is bean.

Spring 容器作为管理 Key 值对,Key 作为 ID/Name,值是 bean。