SeamFramework.orgCommunity Documentation
Hasta ahora, hemos visto algunos ejemplos de anotaciones de tipo ámbito. El ámbito de un Web Bean determina el ciclo de vida de instancias del Web Bean. El ámbito también determina qué clientes se refieren a qué instancias del Web Bean. Según la especificación de Web Beans, un ámbito determina:
Cuándo se crea una nueva instancia de un Web Bean con ese ámbito
Cuándo se destruye una instancia existente de cualquier Web Bean con ese ámbito
Qué referencias se refieren a una instancia de un Web Bean con ese ámbito
Por ejemplo, si tenemos una sesión con ámbito Web Bean, UsuarioActual
, todos los Web Beans que son llamados en el contexto de la misma HttpSession
verán la misma instancia del UsuarioActual
. Dicha instancia se creará automáticamente la primera vez que se necesite un UsuarioActual
en esa sesión, y se destruirá automáticamente al terminar la sesión.
Web Beans ofrece un modelo contextual extensible. Es posible definir nuevos ámbitos creando una nueva anotación de tipo de ámbito:
@Retention(RUNTIME)
@Target({TYPE, METHOD})
@ScopeType
public @interface ClusterScoped {}
Claro está que esa es la parte fácil. Para que este tipo de ámbito sea útil, necesitaremos también definir un objeto Contexto
que implemente el ámbito. La implementación de un Contexto
suele ser una tarea muy técnica, únicamente destinada a desarrollo de marco.
Podemos aplicar un tipo de anotación de ámbito a una clase de implementación de Web Bean para especificar el ámbito del Web Bean:
@ClusterScoped
public class SecondLevelCache { ... }
Por lo general, se utilizará uno de los ámbitos incorporados de Web Beans.
Web Beans define cuatro ámbitos incorporados:
@RequestScoped
@SessionScoped
@ApplicationScoped
@ConversationScoped
Para una aplicación de red que utilice Web Beans:
cualquier petición de servlet tiene acceso a petición activa, sesión y ámbitos de aplicación, y adicionalmente,
cualquier petición de JSF tiene acceso a un ámbito de conversación activo.
Los ámbitos de petición y aplicación también están activos:
durante invocaciones de métodos remotos EJB,
durante pausas EJB,
durante la entrega de mensaje a un bean controlado por mensajes, y
durante invocaciones de servicio de red.
Si la aplicación trata de invocar un Web Bean con un ámbito que no tiene un contexto activo, el administrador de Web Bean produce una ContextNotActiveException
de Web Bean en tiempo de ejecución.
Tres de los ámbitos incorporados deben ser extremadamente familiares a cualquier desarrollador de Java EE, por eso no perdamos tiempo en explicarlos aquí. No obstante, uno de los ámbitos es nuevo.
El ámbito de conversación de Web Beans es un poco parecido al ámbito de sesión tradicional en que mantiene el estado asociado con el usuario del sistema y abarca varias peticiones al servidor. Sin embargo, a diferencia del ámbito de sesión, el ámbito de conversación:
está demarcado explícitamente por la aplicación, y
mantiene un estado asociado con una ficha de navegador de red determinada en una aplicación JSF.
Una conversación representa una tarea, una unidad de trabajo desde el punto de vista del usuario. El contexto de conversación mantiene un estado asociado con lo que el usuario está actualmente trabajando. Si el usuario está trabajando en varias tareas al mismo tiempo, habrá múltiples conversaciones.
El contexto de conversación está activo durante cualquier petición de JSF. Sin embargo, la mayoría de las conversaciones se destruyen al final de la petición. Si una conversación debe mantener un estado a través de múltiples peticiones, debe ser explícitamente promovida a conversación-larga.
Web Beans ofrece un Web Bean incorporado para controlar el ciclo de vida de conversaciones en una aplicación JSF. Dicho Web Bean puede obtenerse por inyección:
@Current Conversation conversation;
Para iniciar la conversación asociada con la petición actual a una conversación larga, llame al método begin()
desde el código de aplicación. Para programar que el actual contexto de conversación larga se destruya al final de la petición actual, llame a end()
.
En el ejemplo a continuación, un Web Bean de conversación en ámbito controla la conversación con la que está asociada.
@ConversationScoped @Stateful
public class OrderBuilder {
private Order order;
private @Current Conversation conversation;
private @PersistenceContext(type=EXTENDED) EntityManager em;
@Produces public Order getOrder() {
return order;
}
public Order createOrder() {
order = new Order();
conversation.begin();
return order;
}
public void addLineItem(Product product, int quantity) {
order.add( new LineItem(product, quantity) );
}
public void saveOrder(Order order) {
em.persist(order);
conversation.end();
}
@Remove
public void destroy() {}
}
Este Web Bean puede controlar su propio ciclo de vida mediante la API de Conversación
. No obstante, algunos otros Web Beans tienen un ciclo de vida que depende totalmente de otro objeto.
El contexto de conversación se propaga automáticamente con cualquier petición de JSF (presentación de formulario JSF). No se propaga automáticamente con peticiones sin caras, por ejemplo, la navegación mediante un enlace.
Podemos forzar la propagación de una conversación con una petición sin-caras al incluir el identificador único de la conversación como un parámetro de petición. La especificación de Web Beans reserva el parámetro llamado cid
para este uso. El único identificador de la conversación se puede obtener del objeto Conversation
, el cual tiene el nombre de Web Beans conversation
.
Por consiguiente, el siguiente enlace propaga la conversación:
<a href="/addProduct.jsp?cid=#{conversation.id}" >Add Product</a >
El administrador de Web Bean también se requiere para propagar conversaciones a través de cualquier redirección, incluso si la conversación no está marcada como larga. Esto facilita mucho la implementación del patrón de POST-luego-redirigir, sin recurrir a construcciones frágiles tales como un objeto "flash". En este caso, el administrador de Web Bean agrega automáticamente un parámetro a la URL de redirección.
Con el fin de preservar recursos, el administrador de Web Bean puede destruir una conversación y todo el estado en su contexto en cualquier momento. Una implementación del administrador de Web Bean normalmente hace esto con base en alguna clase de pausa aunque la especificación de Web Beans no lo requiere. La pausa es el periodo de inactividad anterior a la destrucción de la conversación.
El objeto de Conversación
proporciona un método para configurar el tiempo de espera. Se trata de una ayuda para el administrador de Web Bean quién tiene la libertad de pasar por alto la configuración.
conversation.setTimeout(timeoutInMillis);
Además de los cuatro ámbitos incorporados, Web Beans ofrece el ámbito seudo dependiente. Este es el ámbito para el Web Bean que no declare explícitamente un tipo de ámbito.
Por ejemplo, este Web Bean tiene el ámbito de tipo @Dependent
:
public class Calculator { ... }
Cuando un punto de inyección de un Web Bean apunta a un Web Bean dependiente, una nueva instancia del Web Bean dependiente es creada cada vez que el primer Web Bean sea instanciado. Las instancias de Web Beans dependientes nunca se comparten entre Web Beans o puntos diferentes de inyección. Ellas son objetos dependientes de alguna otra instancia de Web Bean.
Las instancias dependientes de Web Bean se destruyen cuando la instancia de la que dependen es destruida.
Web Beans facilita la obtención de una instancia dependiente de una clase de Java o bean EJB, incluso si la clase o el bean EJB ya se declaró como Web Bean con algún otro tipo de ámbito.
La anotación de enlace incorporada @New
permite definición implícita de un Web Bean dependiente en un punto de inyección. Imagine que declara el siguiente campo inyectado:
@New Calculator calculator;
Entonces un Web Bean con ámbito @Dependent
, tipo de enlace @New
, tipo de API Calculator
, clase de implementación Calculator
y tipo de despliegue @Standard
está definido de modo implícito.
Esto es cierto incluso si Calculator
está ya declarado con un tipo de ámbito diferente, por ejemplo:
@ConversationScoped
public class Calculator { ... }
Por lo tanto cada uno de los siguientes atributos inyectados obtiene una instancia diferente a Calculator
:
public class PaymentCalc {
@Current Calculator calculator;
@New Calculator newCalculator;
}
El campo calculadora
tiene una instancia de conversación-en ámbito de Calculator
inyectada. El campo newCalculator
tiene una nueva instancia de Calculator
inyectada con un ciclo de vida vinculado al propietario de PaymentCalc
.
La función es particularmente útil con métodos de productor, así como veremos en el siguiente capítulo.