Recherche…


Portée singleton

Si un bean est défini avec la portée singleton, une seule instance d'objet unique sera initialisée dans le conteneur Spring. Toutes les demandes adressées à ce bean renverront la même instance partagée. C'est la portée par défaut lors de la définition d'un bean.

Compte tenu de la classe MyBean suivante:

public class MyBean {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyBean.class);
    private String property;

    public MyBean(String property) {
        this.property = property;
        LOGGER.info("Initializing {} bean...", property);
    }

    public String getProperty() {
        return this.property;
    }

    public void setProperty(String property) {
        this.property = property;
    }
}

On peut définir un bean singleton avec l’annotation @Bean:

@Configuration
public class SingletonConfiguration {

    @Bean
    public MyBean singletonBean() {
        return new MyBean("singleton");
    } 
}

L'exemple suivant extrait deux fois le même bean du contexte Spring:

MyBean singletonBean1 = context.getBean("singletonBean", MyBean.class);
singletonBean1.setProperty("changed property");

MyBean singletonBean2 = context.getBean("singletonBean", MyBean.class);

Lors de la connexion de la propriété singletonBean2, le message "Propriété modifiée" sera affiché, car nous venons de récupérer la même instance partagée.

Étant donné que l'instance est partagée entre différents composants, il est recommandé de définir la portée singleton pour les objets sans état.

Haricots singleton paresseux

Par défaut, les beans singleton sont pré-instanciés. Par conséquent, l'instance d'objet partagé sera créée lors de la création du conteneur Spring. Si nous démarrons l'application, le message "Initializing singleton bean ..." sera affiché.

Si nous ne voulons pas que le bean soit pré-instancié, nous pouvons ajouter l'annotation @Lazy à la définition du bean. Cela empêchera le haricot d'être créé jusqu'à ce qu'il soit demandé pour la première fois.

@Bean
@Lazy
public MyBean lazySingletonBean() {
    return new MyBean("lazy singleton");
}

Maintenant, si nous démarrons le conteneur Spring, aucun message "Initializing lazy singleton bean ..." ne s'affichera. Le haricot ne sera pas créé tant qu'il n'aura pas été demandé pour la première fois:

logger.info("Retrieving lazy singleton bean...");
context.getBean("lazySingletonBean");

Si nous exécutons l'application avec les beans singleton et lazy singleton définis, elle produira les messages suivants:

Initializing singleton bean...
Retrieving lazy singleton bean...
Initializing lazy singleton bean...

Portée du prototype

Un haricot prototype n'a pas été créé au démarrage du conteneur Spring. Au lieu de cela, une nouvelle instance sera créée à chaque fois qu'une demande de récupération de ce bean sera envoyée au conteneur. Cette étendue est recommandée pour les objets avec état, car son état ne sera pas partagé par les autres composants.

Pour définir un bean prototype, nous devons ajouter l'annotation @Scope en spécifiant le type de portée que nous voulons.

Compte tenu de la classe MyBean suivante:

public class MyBean {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyBean.class);
    private String property;

    public MyBean(String property) {
        this.property = property;
        LOGGER.info("Initializing {} bean...", property);
    }

    public String getProperty() {
        return this.property;
    }

    public void setProperty(String property) {
        this.property = property;
    }
}

Nous définissons une définition de haricot, indiquant sa portée en tant que prototype:

@Configuration
public class PrototypeConfiguration {

    @Bean
    @Scope("prototype")
    public MyBean prototypeBean() {
        return new MyBean("prototype");
    }
}

Pour voir comment cela fonctionne, nous récupérons le bean du conteneur Spring et définissons une valeur différente pour son champ de propriété. Ensuite, nous allons récupérer le bean du conteneur et rechercher sa valeur:

MyBean prototypeBean1 = context.getBean("prototypeBean", MyBean.class);
prototypeBean1.setProperty("changed property");

MyBean prototypeBean2 = context.getBean("prototypeBean", MyBean.class);

logger.info("Prototype bean 1 property: " + prototypeBean1.getProperty());
logger.info("Prototype bean 2 property: " + prototypeBean2.getProperty());

En regardant le résultat suivant, nous pouvons voir comment une nouvelle instance a été créée sur chaque requête de bean:

Initializing prototype bean...
Initializing prototype bean...
Prototype bean 1 property: changed property
Prototype bean 2 property: prototype

Une erreur commune est de supposer que le bean est recréé par invocation ou par thread, ce n'est PAS le cas. Au lieu de cela, une instance est créée PER INJECTION (ou récupération à partir du contexte). Si un haricot de portée Prototype n'est injecté que dans un seul haricot singleton, il n'y aura qu'une seule instance de ce haricot de portée Prototype.

Spring ne gère pas le cycle de vie complet d'un bean prototype: le conteneur instancie, configure, décore et assemble un objet prototype, le transmet au client et n'a plus aucune connaissance de cette instance de prototype.

Étendues supplémentaires dans des contextes Web

Plusieurs portées sont disponibles uniquement dans un contexte d'application Web:

  • request - Une nouvelle instance de bean est créée par requête HTTP
  • session - une nouvelle instance de bean est créée par session HTTP
  • application - une nouvelle instance de bean est créée par ServletContext
  • globalSession - Une nouvelle instance de bean est créée par session globale dans un environnement de portlet (dans l'environnement de servlet, la portée de session globale est égale à la portée de la session)
  • websocket - Une nouvelle instance de bean est créée par session WebSocket

Aucune configuration supplémentaire n'est requise pour déclarer et accéder à des beans de portée Web dans l'environnement Spring Web MVC.

Configuration XML

<bean id="myRequestBean" class="OneClass" scope="request"/>
<bean id="mySessionBean" class="AnotherClass" scope="session"/>
<bean id="myApplicationBean" class="YetAnotherClass" scope="application"/>
<bean id="myGlobalSessionBean" class="OneMoreClass" scope="globalSession"/>

Configuration Java (avant le printemps 4.3)

@Configuration
public class MyConfiguration {

    @Bean
    @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public OneClass myRequestBean() {
        return new OneClass();
    }

    @Bean
    @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public AnotherClass mySessionBean() {
        return new AnotherClass();
    }

    @Bean
    @Scope(value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public YetAnotherClass myApplicationBean() {
        return new YetAnotherClass();
    }

    @Bean
    @Scope(value = WebApplicationContext.SCOPE_GLOBAL_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public OneMoreClass myGlobalSessionBean() {
        return new OneMoreClass();
    }
}

Configuration Java (après Spring 4.3)

@Configuration
public class MyConfiguration {

    @Bean
    @RequestScope
    public OneClass myRequestBean() {
        return new OneClass();
    }

    @Bean
    @SessionScope
    public AnotherClass mySessionBean() {
        return new AnotherClass();
    }

    @Bean
    @ApplicationScope
    public YetAnotherClass myApplicationBean() {
        return new YetAnotherClass();
    }
}

Composants pilotés par annotation

@Component
@RequestScope
public class OneClass {
    ...
}

@Component
@SessionScope
public class AnotherClass {
    ...
}

@Component
@ApplicationScope
public class YetAnotherClass {
    ...
}

@Component
@Scope(scopeName = WebApplicationContext.SCOPE_GLOBAL_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class OneMoreClass {
    ...
}

@Component
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class AndOneMoreClass {
    ...
}


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow