web-dev-qa-db-fra.com

Quelle est la différence entre singleton et prototype bean?

je suis nouveau au printemps et j'ai lu ceci:

Fondamentalement, un haricot a des portées qui définissent leur existence sur l'application

Singleton: signifie une définition de bean unique pour une instance d'objet unique par conteneur Spring IOC.

Prototype: désigne une définition de bean unique pour un nombre quelconque d'instances d'objet.

Alors, quelle est la "instance d'objet".

32
Amira

Prototype scope = Un nouvel objet est créé chaque fois qu'il est injecté/recherché. Il utilisera new SomeClass() à chaque fois.

Singleton scope = (Par défaut)} _ Le même objet est renvoyé chaque fois qu'il est injecté/recherché. Ici, il instanciera une instance de SomeClass et le renverra à chaque fois.

Voir également:

62
LuckyLuke

Regardons simplement ceci dans le code.

Voici un haricot TennisCoach avec la valeur par défautsingletonScope

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

}

Voici un haricot TennisCoach avec prototype scope

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

}

Voici un cours principal:

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

    }
}

Pour singleton scope, le résultat est le suivant:

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

Pour prototype scope, le résultat est le suivant:

Are the two beans same :false
theCoach : com.springdemo.TennisCoach@1b37288
alphaCoach: com.springdemo.TennisCoach@1a57272

J'espère que ça répond à ta question. :RÉ

14
lordzuko

Ajouter à ce qui précède..ne confondez-vous avec le singleton Java . Selon Java Spec, singleton signifie qu'une seule instance de ce bean sera créée par JVM . être créé par contexte d'application . Ainsi, si votre application comporte plus d'un contexte, vous pouvez toujours avoir plus d'une instance pour ce bean.

9
shashi

Ce sont deux modèles de conception créatifs. 

Singleton créera une nouvelle instance lors du premier appel et la renverra lors des appels suivants.

Le prototype renverra une nouvelle instance à chaque fois.

3
guanabara

Singleton Scope: Avec la portée Singleton, une et une seule instance d'un bean est créée avec la définition de bean fournie. Pour les demandes suivantes relatives au même bean, le conteneur Spring renvoie la même instance. 

De la documentation de printemps:

.. lorsque vous définissez une définition de haricot et que celle-ci est définie comme un singleton, le conteneur Spring IoC crée exactement une instance de l'objet défini par cette définition de haricot. Cette instance unique est stockée dans un fichier cache de tels singleton beans, et toutes les demandes ultérieures et les références pour ce bean nommé renvoient l'objet mis en cache ...

Exemple: Disons que nous avons défini un bean accountDao comme ci-dessous:

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

Et deux autres haricots, qui utilisent ce haricot accountDao

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

Spring créera initialement accountDaobean et le mettra en cache. Et puis, pour someBean et anotherBean, il fournira la même instance de accountDao.

Remarque: Si aucune étendue n'est spécifiée avec la définition du bean, Singleton est l'étendue par défaut.

Portée du prototype: Pour la portée du prototype, pour chaque demande de bean, une nouvelle instance du bean sera créée et renvoyée. Ceci est similaire à l'appel de l'opérateurnewen Java pour une classe.

Exemple: Disons que nous avons défini un bean accountDao comme ci-dessous:

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

Et deux autres haricots, qui utilisent ce haricot accountDao

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

Pour SpringBean et anotherBean, Spring renverra deux instances distinctes de l'objet accountDao.

Une différence importante est que, pour la portée du prototype, Spring ne gère pas le cycle de vie complet du bean, le nettoyage doit être effectué à l'aide du code client. 

De la documentation de printemps:

Spring ne gère pas le cycle de vie complet d'un prototype de bean: le fichier conteneur instancie, configure et assemble autrement un objet prototype, et le remet au client, sans autre enregistrement de cette instance de prototype. Ainsi, bien que le cycle de vie d'initialisation Les méthodes de rappel sont appelées sur tous les objets, quelle que soit leur étendue, dans le fichier Dans le cas de prototypes, les rappels de cycle de vie de destruction configurés ne sont pas appelé. Le code client doit nettoyer les objets à portée prototype et libérez des ressources coûteuses que le ou les prototypes de haricots contiennent.

3
Somnath Musib

Je souhaite ajouter quelques informations supplémentaires susceptibles de nous aider à déterminer le sens du terme "instance d'objet" dans les phrases mentionnées. Ce paragraphe de Spring Doc tente de définir "instance d'objet":

Lorsque vous créez une définition de bean, vous créez une recette pour créer des instances actual de la classe définie par cette définition de bean . L'idée qu'une définition de haricot est une recette est importante, car cela signifie que, comme avec une classe, vous pouvez créer plusieurs instances d'objet à partir d'une même recette.

Par conséquent, comme mentionné dans la section ci-dessus, chaque définition de bean peut être considérée comme une classe (en termes d'objet). Selon les données que vous y avez définies (telles que scope, ...), cette classe (ou définition de bean) peut n'avoir qu'une seule instance d'objet (la portée singleton par une seule instance partagée) ou n'importe quel nombre d'instances d'objet portée du prototype en créant une nouvelle instance de bean chaque fois qu'une demande pour ce bean spécifique est faite).

2
MMKarami
  1. Singleton scope est la valeur par défaut.
  2. Les beans Singleton sont créés lors de l'initialisation du contexte de l'application et le même bean est toujours renvoyé.
  3. Le haricot prototype est créé chaque fois qu'il est appelé. Chaque fois que cela s'appelle, nous obtenons un nouvel objet.

Remarque: Un bean de portée quelconque sera créé s'il est référencé par d'autres beans et appelé à l'aide du contexte d'application.

Exemple de code pour vérifier cela. 

public class PrototypeClass {

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

    }

Cela imprimera le texte pertinent lorsque le constructeur est appelé.

pour le code ci-dessous

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

la classe prototype est createdSpring.PrototypeClass@29774679 prototype la classe est createdSpring.PrototypeClass@3ffc5af1, la classe prototype est createdSpring.PrototypeClass@5e5792a0 La classe de prototype est createdSpring.PrototypeClass@26653222 La classe de prototype est createdSpring.PrototypeClass@3532ec19 La classe de prototype est createdSpring.PrototypeClass@68c4039c La classe de prototype est createdSpring.PrototypeClass@ae45eb6 La classe de prototype est createdSpring.PrototypeClass@59f99ea La classe de prototype est createdSpring.PrototypeClass@27efef64 La classe de prototype est createdSpring.PrototypeClass@6f7fd0e6 La classe de prototype est createdSpring.PrototypeClass@47c62251

La définition de haricot est

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

Maintenant, j'ai changé la portée de la définition du bean en singleton. Le constructeur n'est appelé qu'une fois lors de l'initialisation du contexte. Ensuite, j'ai supprimé l'attribut scope et observé le même comportement que singleton.

0
vijay anirudh

Singleton est la même instance dans toute l'application

Le prototype est une nouvelle instance pour chaque nouvelle requête de getBean

0
Kislay Sinha

Portée du prototype: Un nouvel objet est créé chaque fois qu'il est injecté.
Singleton scope: Le même objet est renvoyé à chaque injection. 

La portée du prototype est utilisée pour tous les beans qui ont un état, alors que la portée du singleton devrait être utilisée pour les beans sans état… .. Laissez-moi vous expliquer avec mon exemple. Copiez-le et lancez-le par vous-même pour bien comprendre. Considérons un coach d'interface.

public interface Coach {

    public String getDailyWorkout();

    public String getDailyFortune();

}

Nous avons une autre classe appelée TrackCoach qui implémente 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();
    }    
}

Il existe maintenant une interface FortuneService. 

public interface FortuneService {

    public String getFortune();

}

Il est implémenté par notre classe HappyFortuneService. 

public class HappyFortuneService implements FortuneService {

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

}

Câblons les deux classes et injectons un objet bean d'une classe dans une autre à l'aide de XML. Faisons l'injection de dépendance. Notez que nous pouvons aussi le faire en utilisant une annotation 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>

Notez que scope = singleton

Définissons maintenant notre BeanScopeDemoApp, qui a notre méthode principale. 

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

}

Une fois que vous exécutez le code ci-dessus, vous verrez les résultats suivants: 

Pointing to the same object: true

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

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

Il pointe le même objet et occupe le même emplacement mémoire après l'avoir appelé deux fois. Maintenant, changeons le scope = prototype dans notre fichier XML, sauvegardons-le et exécutez à nouveau BeanScopeDemoApp.
Vous verrez les résultats suivants: 

Pointing to the same object: false

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

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

Cela pointe l'objet différent et occupe les différents emplacements de mémoire après l'avoir appelé deux fois ... Ceci serait une illustration graphique de ce que je viens de dire.  enter image description here  enter image description here

0
Sumit Pokhrel