web-dev-qa-db-fra.com

La valeur par défaut de Spring est-elle singleton ou non?

Pourriez-vous s'il vous plaît expliquer pourquoi Spring crée deux objets pour la configuration des beans illustrée ci-dessous, puisque par défaut, la valeur par défaut de spring est singleton?

La configuration de Spring est ici:

<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>
33
Raj

La portée par défaut de Spring est singleton. C'est juste que votre idée de ce que signifie être un singleton ne correspond pas à la façon dont Spring définit les singletons.

Si vous indiquez à Spring de créer deux beans distincts avec des identifiants différents et la même classe, vous obtenez alors deux beans distincts, chacun ayant une portée singleton. Toute portée singleton signifie que lorsque vous référencez quelque chose avec le même identifiant, vous récupérez la même instance de bean.

Voici comment la documentation de Spring définit la portée de singleton :

Une seule instance partagée d'un bean singleton est gérée, et toutes les demandes de beans avec un ou plusieurs identifiants correspondant à cette définition de bean entraînent le renvoi d'une instance de bean spécifique par le conteneur Spring.

Singleton scope signifie que l'utilisation du même identifiant permet d'extraire le même bean, c'est tout. Tester qu’aucun identifiant n’est référencé dans la même classe n’empêcherait l’utilisation de cartes en tant que haricots et serait compliqué par un proxy avec BeanFactories . fait confiance aux utilisateurs pour savoir ce qu'ils font.

La façon de définir deux noms pour le même bean consiste à utiliser un alias :

Dans une définition de bean elle-même, vous pouvez fournir plusieurs noms pour le bean, en combinant un nom au maximum spécifié par l'attribut id et un nombre quelconque d'autres noms dans l'attribut name. Ces noms peuvent être des alias équivalents au même bean et sont utiles dans certaines situations, telles que permettre à chaque composant d'une application de faire référence à une dépendance commune en utilisant un nom de bean spécifique à ce composant lui-même.

La spécification de tous les alias où le bean est réellement défini n'est toutefois pas toujours adéquate. Il est parfois souhaitable d'introduire un alias pour un haricot défini ailleurs. C'est généralement le cas dans les grands systèmes où la configuration est partagée entre chaque sous-système, chaque sous-système ayant son propre ensemble de définitions d'objet. Dans les métadonnées de configuration basées sur XML, vous pouvez utiliser l'élément pour accomplir cela.

Donc, si vous ajoutez un nom à la configuration du bean:

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

ou créez un alias pour un haricot défini ailleurs:

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

alors "client" et "client2" feront référence à la même instance de bean.

La portée par défaut de Spring est singleton et crée un objet pour toutes les instances, sauf si vous spécifiez explicitement que la portée est un prototype. Vous n'avez pas posté de configuration de printemps. S'il vous plaît postez-le, cela vous donnera une meilleure idée.

6
Anupama Rao

Vous déclarez deux haricots de la même classe. Ce n'est pas pareil.

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

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

}

Et essayez d'accéder à ce haricot à deux endroits, le nombre sera le même. Mais vous avez créé deux beans distincts.

Si vous voulez vérifier si cela fonctionne, essayez:

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

Ce code doit renvoyer true s'il s'agit de la même instance; Mais dans SpringTestClass, vous pouvez ajouter une annotation @Scope ("prototype"). La sortie sera fausse

2
Berrigan

Comme d'autres l'ont mentionné, deux beans devraient être créés à partir du code que vous avez posté. Les singletons sont définis comme suit (dans la documentation de Spring: Singleton Scope )

Une seule instance partagée d'un bean singleton est gérée, et toutes les demandes de beans avec un ou plusieurs identifiants correspondant à cette définition de bean entraînent le renvoi d'une instance de bean spécifique par le conteneur Spring.

Pour plus de clarté, la signification de "instance partagée" est expliquée dans le paragraphe qui suit celui ci-dessus:

toutes les demandes et références suivantes pour ce bean nommé retournent l'objet mis en cache

Lorsqu'un bean singleton est créé, un seul objet bean est instancié et mis en cache. Cela ne concerne que le haricot, et non la classe dont il peut être un exemple. Par exemple,

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

Dans cette configuration composée, "myOtherBean1" et "myOtherBean2" ont des références au même bean "myBean" et donc à la même instance "myPackage.myClass". Si vous modifiez le code pour ajouter un deuxième bean "myPackage.myClass", il sera distinct de "myBean".

Pour bien comprendre cela, reportez-vous également à l’autre portée Spring: le prototype. Extrait de la documentation de printemps pour Prototype Scope :

La portée du prototype de déploiement de bean non singleton se traduit par la création d'une nouvelle instance de bean chaque fois qu'une demande pour ce bean spécifique est faite.

Cela signifie que si nous utilisions le même XML Spring que ci-dessus, "myOtherBean1" et "myOtherBean2" recevraient chacun leurs propres copies distinctes de "myBean", qui n'est encore qu'une instance de "myPackage.myClass".

2
ryoung10

Vous confondez deux concepts différents.

Le mot singleton au printemps est utilisé pour une étendue de haricot, ce qui signifie que le haricot ne sera créé qu'une seule fois pour toute l'application. 

Singleton signifie habituellement le modèle GOF. C'est un modèle orienté objet garantissant qu'il n'y aura qu'une seule instance d'une classe (du moins dans la portée du classLoader). 

1
Gab

L'exemple suivant montre une méthode annotée @Bean appelée deux fois:

@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 () a été appelé une fois dans clientService1 () et une fois dans clientService2 (). Depuis cette méthode crée une nouvelle instance de ClientDaoImpl et le renvoie, vous vous attendriez normalement à avoir 2 instances (une pour chaque service). Ce serait certainement problématique: au printemps, les haricots instanciés ont une portée singleton par défaut. C’est là que la magie intervient: Toutes les classes @Configuration sont sous-classés au moment du démarrage avec CGLIB. Dans la sous-classe, l'enfant La méthode vérifie d’abord le conteneur pour tous les haricots mis en cache (scoped) avant il appelle la méthode parente et crée une nouvelle instance. Notez que à partir de Printemps 3.2, il n’est plus nécessaire d’ajouter CGLIB à votre chemin de classe parce que les classes CGLIB ont été reconditionnées sous org.springframework.cglib et inclus directement dans le ressort-core POT.

0
Adam Ostrožlík