Buscar..


Alcance singleton

Si un bean se define con el alcance de singleton, solo habrá una única instancia de objeto inicializada en el contenedor Spring. Todas las solicitudes a este bean devolverán la misma instancia compartida. Este es el alcance por defecto cuando se define un bean.

Dada la siguiente clase de MyBean:

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

Podemos definir un bean singleton con la anotación @Bean:

@Configuration
public class SingletonConfiguration {

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

El siguiente ejemplo recupera el mismo bean dos veces del contexto de Spring:

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

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

Al registrar la propiedad singletonBean2, se mostrará el mensaje "propiedad modificada" , ya que acabamos de recuperar la misma instancia compartida.

Dado que la instancia se comparte entre diferentes componentes, se recomienda definir el alcance de singleton para objetos sin estado.

Habas singleton perezosos

Por defecto, los beans singleton están pre-instanciados. Por lo tanto, la instancia de objeto compartido se creará cuando se cree el contenedor Spring. Si iniciamos la aplicación, se mostrará el mensaje "Inicializando singleton bean ..." .

Si no queremos que el bean sea pre-instanciado, podemos agregar la anotación @Lazy a la definición del bean. Esto evitará que el bean se cree hasta que se solicite por primera vez.

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

Ahora, si iniciamos el contenedor Spring, no aparecerá el mensaje "Inicializando el bean singleton lento ..." . El bean no se creará hasta que se solicite por primera vez:

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

Si ejecutamos la aplicación con los frijoles singleton y perezosos singleton definidos, producirá los siguientes mensajes:

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

Alcance prototipo

Un bean de ámbito prototipo no se crea previamente en el inicio del contenedor Spring. En su lugar, se creará una nueva instancia nueva cada vez que se envíe una solicitud para recuperar este bean al contenedor. Este alcance se recomienda para objetos con estado, ya que su estado no será compartido por otros componentes.

Para definir un bean de ámbito de prototipo, debemos agregar la anotación @Scope, especificando el tipo de ámbito que queremos.

Dada la siguiente clase de MyBean:

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

Definimos una definición de bean, indicando su alcance como prototipo:

@Configuration
public class PrototypeConfiguration {

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

Para ver cómo funciona, recuperamos el bean del contenedor Spring y establecemos un valor diferente para su campo de propiedad. A continuación, volveremos a recuperar el bean del contenedor y buscaremos su valor:

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

Si observamos el siguiente resultado, podemos ver cómo se ha creado una nueva instancia en cada solicitud de bean:

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

Un error común es asumir que el bean se vuelve a crear por invocación o por hilo, este NO es el caso. En su lugar, se crea una instancia POR INYECCIÓN (o recuperación del contexto). Si un bean Prototipo con ámbito solo se inyecta en un único bean singleton, solo habrá una instancia de ese frijol Prototype.

Spring no gestiona el ciclo de vida completo de un bean prototipo: el contenedor crea instancias, configura, decora y ensambla un objeto prototipo, se lo entrega al cliente y luego no tiene conocimiento de esa instancia de prototipo.

Ámbitos adicionales en contextos web-conscientes

Hay varios ámbitos que están disponibles solo en un contexto de aplicación compatible con la web:

  • solicitud - se crea una nueva instancia de bean por solicitud HTTP
  • sesión - se crea una nueva instancia de bean por sesión HTTP
  • aplicación - se crea una nueva instancia de bean por ServletContext
  • globalSession : la nueva instancia de bean se crea por sesión global en el entorno Portlet (en el ámbito de sesión global del entorno Servlet es igual al alcance de la sesión)
  • websocket - se crea una nueva instancia de bean por sesión de WebSocket

No se requiere configuración adicional para declarar y acceder a beans de ámbito web en el entorno Spring Web MVC.

Configuración 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"/>

Configuración de Java (antes de la primavera 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();
    }
}

Configuración de Java (después de la primavera 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();
    }
}

Componentes impulsados ​​por anotación

@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
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow