53

我是春天的新手,我读到了这个:

基本上,一个 bean 具有定义它们在应用程序中存在的范围

Singleton:表示每个 Spring IOC 容器的单个对象实例的单个 bean 定义。

原型:意味着对任意数量的对象实例的单个 bean 定义。

那么什么是“对象实例”。

4

9 回答 9

90

原型范围= 每次注入/查找时都会创建一个新对象。new SomeClass()每次都会用到。

单例范围= (默认)每次注入/查找时都返回相同的对象。在这里,它将实例化一个实例,SomeClass然后每次都返回它。

也可以看看:

于 2013-04-17T11:07:19.050 回答
28

让我们通过代码简单地查看一下。

以下是具有默认singletonScope的 TennisCoach Bean

@Component
@Scope("singleton")
public class TennisCoach implements Coach {

    public TennisCoach(){

    }

    @Autowired
    public void setFortuneService(FortuneService fortuneService) {
        this.fortuneService = fortuneService;
    }

    @Override
    public String getDailyWorkout() {
        return "Practice your backhand volley";
    }

    @Override
    public String getDailyFortune() {
        return "Tennis Coach says : "+fortuneService.getFortune();
    }

}

以下是具有原型范围的 TennisCoach Bean

@Component
@Scope("prototype")
public class TennisCoach implements Coach {

    public TennisCoach(){
        System.out.println(">> TennisCoach: inside default constructor");
    }

    @Autowired
    public void setFortuneService(FortuneService fortuneService) {
        System.out.println(">> Tennis Coach: inside setFortuneService");
        this.fortuneService = fortuneService;
    }

    @Override
    public String getDailyWorkout() {
        return "Practice your backhand volley";
    }

    @Override
    public String getDailyFortune() {
        return "Tennis Coach says : "+fortuneService.getFortune();
    }

}

以下是一个主类:

public class AnnotationDemoApp {

    public static void main(String[] args) {


        // read spring config file
        ClassPathXmlApplicationContext context =
            new ClassPathXmlApplicationContext("applicationContext.xml");

       // get the bean from the spring container
       Coach theCoach = context.getBean("tennisCoach",Coach.class);
       Coach alphaCoach = context.getBean("tennisCoach",Coach.class);
       // call a method on the bean
       System.out.println("Are the two beans same :" + (theCoach==alphaCoach));

       System.out.println("theCoach : " + theCoach);
       System.out.println("alphaCoach: "+ alphaCoach);


       context.close()

    }
}

对于单例范围,输出为:

Are the two beans same :true
theCoach : com.springdemo.TennisCoach@2a53142
alphaCoach: com.springdemo.TennisCoach@2a53142

对于原型范围,输出为:

Are the two beans same :false
theCoach : com.springdemo.TennisCoach@1b37288
alphaCoach: com.springdemo.TennisCoach@1a57272
于 2016-09-09T06:22:33.030 回答
14

添加到上面..不要与java单例混淆。根据 JAVA 规范,单例意味着每个 JVM 只会创建该 bean 的一个实例。但在春季单例中,意味着每个应用程序上下文将为该特定 bean 创建一个实例。因此,如果您的应用程序有多个上下文,您仍然可以为该 bean 提供多个实例。

于 2013-04-17T20:52:36.110 回答
4

它们都是创造型设计模式。

Singleton,将在第一次调用中创建一个新实例,并在后续调用中返回它。

Prototype 每次都会返回一个新的实例。

于 2013-04-17T11:12:08.740 回答
4

单例范围:使用单例范围,使用提供的 bean 定义创建一个且只有一个 bean 实例,对于同一个 bean 的后续请求,Spring 容器将返回相同的实例。

来自 Spring 文档:

.. 当您定义一个 bean 定义并将其限定为单例时,Spring IoC 容器会创建该 bean 定义所定义的对象的一个​​实例。此单个实例存储在此类单例 bean 的缓存中,并且该命名 bean 的所有后续请求和引用都返回缓存对象...

示例:可以说,我们定义了一个 bean accountDao,如下所示:

<bean id="accountDao" class="" />

还有另外两个 bean,它使用这个accountDaobean

<bean id="someBean" ref="accountDao" /> 
<bean id="anotherBean" ref="accountDao" />

Spring 最初会创建accountDaobean 并缓存它。然后for someBeanas well anotherBean,它将提供相同的实例accountDao

注意:如果 bean 定义没有指定范围,则 Singleton 是默认范围。

原型作用域:对于原型作用域,对于 bean 的每个请求,都会创建并返回一个新的 bean 实例。这类似于在 java 中为类调用new运算符。

示例:可以说,我们定义了一个 bean accountDao,如下所示:

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

还有另外两个 bean,它使用这个accountDaobean

<bean id="someBean" ref="accountDao" /> 
<bean id="anotherBean" ref="accountDao" />

对于 someBean 和 anotherBean,Spring 会返回两个独立的 accountDao 对象实例。

一个重要的区别是,对于原型作用域,Spring 不管理 bean 的完整生命周期,清理需要由客户端代码完成。

来自 Spring 文档:

Spring 不管理原型 bean 的完整生命周期:容器实例化、配置和以其他方式组装原型对象,并将其交给客户端,而没有进一步记录该原型实例。因此,尽管在所有对象上调用初始化生命周期回调方法而不考虑范围,但在原型的情况下,不会调用配置的销毁生命周期回调。客户端代码必须清理原型范围的对象并释放原型 bean 持有的昂贵资源。

于 2015-09-07T10:54:54.687 回答
3
  1. 单例范围是默认的。
  2. 单例 bean 在应用上下文初始化期间创建,并且始终返回相同的 bean。
  3. 原型 bean 在被调用时被创建。每次调用它都会得到一个新对象。

注意:如果 Bean 被其他 Bean 引用并使用 Application 上下文调用,则将创建具有任何范围的 Bean。

用于检查这一点的示例代码。

public class PrototypeClass {

        PrototypeClass()
        {
            System.out.println("prototype class is created"+this.toString());
        }

    }

这将在调用构造函数时打印相关文本。

对于下面的代码

for(int i=0;i<10;i++) {
   PrototypeClass pct= (PrototypeClass) context.getBean("protoClass");
}

创建原型类Spring.PrototypeClass@29774679 创建原型类Spring.PrototypeClass@3ffc5af1 创建原型类Spring.PrototypeClass@5e5792a0 创建原型类Spring.PrototypeClass@26653222 创建原型类Spring.PrototypeClass@3532ec19 创建原型类Spring.PrototypeClass@68c4039c 原型类已创建Spring.PrototypeClass@ae45eb6 原型类已创建Spring.PrototypeClass@59f99ea 原型类已创建Spring.PrototypeClass@27efef64 原型类已创建Spring.PrototypeClass@6f7fd0e6 原型类已创建Spring.PrototypeClass@47c62251

bean定义是

<bean id="protoClass" class="Spring.PrototypeClass" scope="prototype</bean>

现在我将 bean 定义中的范围更改为 singleton 。在上下文初始化期间只调用一次构造函数。接下来,我删除了 scope 属性并观察到与单例相同的行为。

于 2017-11-08T09:40:49.347 回答
2

我想添加一些额外的信息,可以帮助我们找出上述句子中“对象实例”的含义。Spring Doc 中的这一段尝试定义“对象实例”:

当您创建一个 bean 定义时,您创建了一个用于创建由该 bean 定义定义的类的实际 实例的方法。bean 定义是一个配方的想法很重要,因为这意味着,与一个类一样,您可以从一个配方创建许多对象实例。

因此,如上一节所述,每个 bean 定义都可以被视为一个类(就面向对象而言)。根据您在其中定义的数据(例如范围,...),这个类(或 bean 定义)可能只有一个对象实例(只有一个共享实例的单例范围)或任意数量的对象实例(例如每次对特定 bean 发出请求时,通过创建一个新的 bean 实例来创建原型作用域)。

于 2017-09-17T14:28:50.567 回答
1

原型作用域:每次注入时都会创建一个新对象。
单例作用域:每次注入都返回同一个对象。

原型范围用于所有有状态的 bean,而单例范围应用于无状态 bean。让我用我的例子来解释。请自行复制运行,以便清楚了解。考虑一个界面教练。

public interface Coach {

    public String getDailyWorkout();

    public String getDailyFortune();

}

我们有另一个名为 TrackCoach 的类,它实现了 Coach。

public class TrackCoach implements Coach {

    private FortuneService fortuneService;


    public TrackCoach(FortuneService fortuneService) {
        this.fortuneService = fortuneService;
    }

    @Override
    public String getDailyWorkout() {
        return "Run a hard 5k";
    }

    @Override
    public String getDailyFortune() {
        return "Just Do it: " + fortuneService.getFortune();
    }    
}

现在有一个FortuneService接口。

public interface FortuneService {

    public String getFortune();

}

它由我们的 HappyFortuneService 类实现。

public class HappyFortuneService implements FortuneService {

    @Override
    public String getFortune() {
        return "Today is your lucky day!";
    }

}

让我们连接这两个类并使用 Xml 将一个类的对象 bean 注入到另一个类中。让我们执行依赖注入。请注意,我们也可以使用 java 注释来做到这一点。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">


    <!-- Define your beans here -->

    <!--  define the dependency  -->
    <bean id = "myFortuneService"
        class = "com.luv2code.springdemo.HappyFortuneService">
    </bean>

    <bean id = "myCoach"
        class = "com.luv2code.springdemo.TrackCoach"
        scope = "singleton">


        <!-- set up construction injection -->
        <constructor-arg ref = "myFortuneService" />
    </bean>

</beans>

请注意scope = singleton.

现在让我们定义我们的 BeanScopeDemoApp,它有我们的 main 方法。

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanScopeDemoApp {

    public static void main(String[] args) {

        // load the spring configuration file 
        ClassPathXmlApplicationContext context = 
                new ClassPathXmlApplicationContext("beanScope-applicationContext.xml");

        // retrieve bean from spring container 
        Coach theCoach = context.getBean("myCoach", Coach.class);

        Coach alphaCoach = context.getBean("myCoach", Coach.class);

        // check if they are the same 
        boolean result = (theCoach == alphaCoach);

        // print out the results 
        System.out.println("\nPointing to the same object: " + result);

        System.out.println("\nMemory location for theCoach: " + theCoach);

        System.out.println("\nMemory location for alphaCoach: " + alphaCoach +"\n");

        // close the context 
        context.close();
    }

}

运行上述代码后,您将看到以下结果:

Pointing to the same object: true

Memory location for theCoach: com.luv2code.springdemo.TrackCoach@16515bb7

Memory location for alphaCoach: com.luv2code.springdemo.TrackCoach@16515bb7

它指向同一个对象并在调用它两次后占用相同的内存位置。现在让我们更改scope = prototype我们的 XML 文件,保存它并再次运行 BeanScopeDemoApp。
您将看到以下结果:

Pointing to the same object: false

Memory location for theCoach: com.luv2code.springdemo.TrackCoach@6d4d203d

Memory location for alphaCoach: com.luv2code.springdemo.TrackCoach@627fbcda

它指向不同的对象并在调用两次后占用不同的内存位置。这将是我刚才所说的图形说明。 在此处输入图像描述 在此处输入图像描述

于 2017-09-27T20:49:02.523 回答
0

单例是跨应用程序的相同实例

原型是 getBean 的每个新请求的新实例

于 2015-05-26T06:30:24.300 回答