Cuando declaramos un bean ya sea usando archivos xml o anotaciones, sólo estamos definiendo una plantilla para la creación del bean, y no una instancia del bean. Recién cuando solicitemos una referencia al bean, Spring decidirá que instancia debe ser retornada, para esto se tiene en cuenta el valor "scope" del bean.
Los scopes soportados en son:
singleton :
Crea una sola instancia del bean por contenedor. Es el scope usado por defecto
prototype :
Crea una nueva instancia del bean cada vez que se pida una referencia al contenedor.
request :
Crea una nueva instancia por cada request HTTP. Sólo es válido en el contexto de aplicaciones Web. Simplificando las cosas podemos decir que se dan los siguientes pasos cada vez que el contenedor recibe un request:
a) El contenedor recibe el request
b) Se crean los objetos que tienen scope= WebApplicationContext.SCOPE_REQUEST ("request")
c) Cualquier llamada al contenedor para pedir una referencia al bean con scope="request", devuelve el bean creado en el punto b.
d) El contenedor termina de atender el request.
e) Los beans con scope="request" son eliminados.
session :
Crea una nueva instancia por cada session HTTP. Sólo es válido en el contexto de aplicaciones Web. Simplificando las cosas podemos decir que se dan los siguientes pasos:
a) Se crea la session Http.
b) Se crean los objetos que tienen scope= WebApplicationContext.SCOPE_SESSION ("session")
c) Cualquier llamada al contenedor para pedir una referencia al bean con scope="session", devuelve el bean creado en el punto b.
d) Se cierra la session Http.
e) Los beans con scope="session" son eliminados.
global-session :
Crea una nueva instancia por cada session HTTP global. Sólo es válido en el contexto de portlets.
Inyectar beans con scope distinto a singleton y prototype.
Imaginemos que nosotros queremos tener un objeto que sea creado cada vez que el contenedor recibe un request.
Entonces podríamos crear los siguiente
@Component
Controlador
@Autowired
RequestInfo requestInfo
@Component
RequestInfo
Con la configuración anterior tenemos el siguiente problema:
- El componente RequestInfo tiene scope="singleton", por tanto siempre será el mismo objeto.
Para tratar de arreglar eso hagamos el siguiente cambio:
@Component
@Scope(value = "request")
RequestInfo
Con esta configuración tenemos el siguiente problema:
- El componente Controlador tiene scope="singleton" entonces el contenedor al inicializarse creará una instancia de este bean y también seteará todas sus dependencias, en este caso seteará su atributo "requestInfo", y esta instancia de RequestInfo no será creada de nuevo con cada request.
Para arreglar esto hacemos lo siguiente:
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
RequestInfo
Con esta configuración, cuando el contenedor inicialice el bean "Controlador", seteará en la propiedad "requestInfo" un proxy al Componente RequestInfo. De esta manera cuando se requiera llamar a un método del RequestInfo, ese método será recibido por el proxy y este a su vez llamará al método en el objeto adecuado que es creado de acuerdo al valor del scope en este caso "request".
Algunos apuntes
Para setear el scope usar lo siguiente:
Usando archivos XML:
<bean class="Controlador" scope="prototype"/>
@Component
@Scope(value = "prototype")
public class Controlador {
Para setear el modo de proxy usar:
Usando archivos XML:
<bean class="RequestInfo" scope="request">
<aop:scoped-proxy proxy-target-class="true"/>
</bean>
@Component
@Scope(value = "entrevista", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestInfo{
