Spring singleton和prototype bean之间的区别是什么?

Spring singleton和prototype bean之间的区别是什么?,spring,dependency-injection,Spring,Dependency Injection,我是春天的新手,我读到: 基本上,bean具有定义其在应用程序上存在的范围 Singleton:表示每个SpringIOC容器对单个对象实例的单个bean定义 Prototype:表示对任意数量的对象实例的单个bean定义 那么“对象实例”是什么呢?原型范围=每次注入/查找新对象时都会创建一个新对象。每次都将使用newsomeclass() 单例作用域=(默认)每次注入/查找同一对象时都返回该对象。在这里,它将实例化SomeClass的一个实例,然后每次返回它 另请参见: 它们都是创造性的设

我是春天的新手,我读到:

基本上,bean具有定义其在应用程序上存在的范围

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

Prototype:表示对任意数量的对象实例的单个bean定义


那么“对象实例”是什么呢?

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

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

另请参见:


它们都是创造性的设计模式

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


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

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

Singleton是应用程序中的同一个实例


Prototype是getBean的每个新请求的新实例

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

从Spring文档中:

。。当您定义一个bean定义并将其范围限定为单例时, SpringIOC容器只创建一个对象实例 由该bean定义定义。此单个实例存储在 此类单例bean的缓存,以及所有后续请求和 该命名bean的引用将返回缓存的对象

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

<bean id="accountDao" class="" />
<bean id="accountDao" class="" scope="prototype"/>
Spring最初将创建
accountDao
bean并缓存它。然后对于
someBean
以及
anotherBean
,它将提供与
accountDao
相同的实例

注意:如果bean定义没有指定作用域,那么Singleton是默认作用域

原型范围:对于原型范围,对于bean的每个请求,将创建并返回一个新的bean实例。这类似于在java中为类调用new操作符

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

<bean id="accountDao" class="" />
<bean id="accountDao" class="" scope="prototype"/>
对于someBean和另一个Bean,Spring将返回accountDao对象的两个独立实例

一个重要的区别是,对于prototype范围,Spring不管理bean的整个生命周期,清理需要由客户机代码完成

从Spring文档中:

Spring不管理原型bean的整个生命周期: 容器实例化、配置和以其他方式组装 原型对象,并将其交给客户机,无需进一步记录 那个原型的实例。因此,虽然初始化的生命周期 在 对于原型,配置的销毁生命周期回调不可用 打电话。客户机代码必须清理原型范围的对象和 释放原型bean所持有的昂贵资源


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

下面是一个TennisCoach Bean,默认范围为
singleton

@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
对于原型范围,输出为:

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

我想补充一些额外的信息,帮助我们找出上述句子中“对象实例”的含义。Spring文档中的这一段试图定义“对象实例”:

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


因此,正如上面部分提到的,每个bean定义都可以被视为一个类(从面向对象的角度)。根据您在其中定义的数据(例如范围,…),该类(或bean定义)可能只有一个对象实例(只有一个共享实例的单例范围)或任意数量的对象实例(例如,每次请求特定bean时通过创建新的bean实例来定义原型范围).

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

Prototype作用域用于所有有状态的bean,而singleton作用域应用于无状态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();
    }    
}
现在有了一个服务接口

public interface FortuneService {

    public String getFortune();

}
它是由我们班的幸福服务来实现的

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>
运行上述代码后,您将看到以下结果
Pointing to the same object: false

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

Memory location for alphaCoach: com.luv2code.springdemo.TrackCoach@627fbcda
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");
}
<bean id="protoClass" class="Spring.PrototypeClass" scope="prototype</bean>