春季默认范围是单身吗?

时间:2015-07-25 18:52:06

标签: java spring dependency-injection singleton spring-ioc

你能否解释一下为什么Spring为下面显示的bean配置创建了两个对象,因为默认情况下spring默认范围是singleton?

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>

9 个答案:

答案 0 :(得分:49)

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

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

以下是the Spring documentation defines singleton scope

的方式
  

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

Singleton范围意味着使用相同的id检索相同的bean,即all。测试没有两个id引用同一个类会妨碍使用map作为bean,并且通过使用BeanFactories代理事物会很复杂。 对于Spring来说,这将涉及大量工作而没有什么好处,相反,它相信用户知道他们正在做什么。

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

  

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

     

但是,指定实际定义bean的所有别名并不总是足够的。有时需要为其他地方定义的bean引入别名。在大型系统中通常就是这种情况,其中配置在每个子系统之间分配,每个子系统具有其自己的一组对象定义。在基于XML的配置元数据中,您可以使用该元素来完成此任务。

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

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

或为其他地方定义的bean创建别名:

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

然后“customer”和“customer2”将引用相同的bean实例。

答案 1 :(得分:6)

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

答案 2 :(得分:2)

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

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

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

}

并尝试在两个位置访问此bean,数字将相同。但你所做的是创建两个独立的bean。

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

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

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

答案 3 :(得分:2)

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

  

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

为了清楚这一点,&#34;共享实例背后的含义&#34;在上面的段落中解释:

  

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

创建单例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>

在这个组成的配置中,&#34; myOtherBean1&#34;和&#34; myOtherBean2&#34;引用相同的&#34; myBean&#34; bean因此相同&#34; myPackage.myClass&#34;实例。如果您更改了代码以添加第二个&#34; myPackage.myClass&#34; bean,它将与&#34; myBean&#34;。

区别开来

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

  

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

这意味着如果我们使用与上面相同的Spring XML,&#34; myOtherBean1&#34;和&#34; myOtherBean2&#34;每个人都会收到他们自己不同的副本&#34; myBean&#34;这仍然是&#34; myPackage.myClass&#34;。

的一个实例

答案 4 :(得分:1)

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

spring中的单词single用于bean作用域,这意味着bean只会为整个应用程序创建一次。

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

答案 5 :(得分:0)

  

以下示例显示了一个@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()已在clientService1()中调用一次,并在   clientService2()。由于此方法创建了一个新实例   ClientDaoImpl并将其返回,您通常希望拥有2   实例(每个服务一个)。那肯定是   有问题的:在春季,实例化的bean具有单例作用域   默认。这就是神奇的地方:所有@Configuration类   在启动时使用CGLIB进行子类化。在子类中,孩子   方法首先检查容器中是否有任何缓存的(作用域)bean   它调用父方法并创建一个新实例。请注意,截至   在Spring 3.2中,不再需要将CGLIB添加到您的类路径中   因为CGLIB类已经在   org.springframework.cglib并直接包含在spring-core中   JAR。

答案 6 :(得分:0)

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

因此Spring单例与Java单例不同。请勿混淆这两者。

答案 7 :(得分:0)

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

如果我们写

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

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

Spring容器作为管理键值对,键作为ID /名称,值是bean。

答案 8 :(得分:0)

spring 默认范围是单例。一旦 bean 将被创建并在其整个生命周期中使用相同的 bean。