Puede crear una clase de implementación de bean para un bean de sesión con estado como se introduce
en la especificación de Enterprise JavaBeans™ (EJB) 1.0 y significativamente simplificado mediante la
especificación EJB 3.0.
Un bean con estado es un tipo de bean de sesión que está diseñado para que lo
utilice un solo cliente durante su vida útil y mantiene un estado conversacional con el cliente al que está
llamando.
Antes de empezar
Asegúrese de que comprende las reglas de herencia para cada anotación
que implemente. Por ejemplo, la anotación @TransactionManagement se codifica sólo en la clase de bean de
sesión con estado. No puede utilizar la anotación @TransactionManagement en la clase que amplía, o ninguna clase superior en
el árbol de herencia de clase.
Acerca de esta tarea
Los beans de sesión con estado pueden tener las vistas siguientes: una vista local no
de interfaz (novedad en EJB 3.1), local empresarial, remota empresarial, local de EJB 2.1 y vistas de cliente remoto EJB2.1. Un ejemplo es un carro de la compra al que el cliente añade
artículos durante una sesión de compra en línea.
En el ejemplo siguiente se muestra un bean de sesión singleton básico:
package com.ibm.example;
public interface ShoppingCart {
void addToCart (Object o);
Collection getContents();
}
package com.ibm.example;
@Stateful
public class ShoppingCartBean implements ShoppingCart {
private ArrayList contents = new ArrayList();
public void addToCart (Object o) {
contents.add(o);
}
public Collection getContents() {
return contents;
}
}
Al igual que con otros tipos de enterprise bean, también puede declarar
metadatos para beans de sesión con estado en el descriptor de despliegue en lugar de utilizar anotaciones; por
ejemplo:
<?xml version="1.0"?>
<ejb-jar
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
version="3.1">
<enterprise-beans>
<ejb-name>ShoppingCartBean</ejb-name>
<business-local>com.ibm.example.ShoppingCart</business-local>
<ejb-class>com.ibm.example.ShoppingCartBean</ejb-class>
<session-type>Stateful</session-type>
</enterprise-beans>
</ejb-jar>
- Codifique los métodos de inicialización y destrucción, teniendo en cuenta que se ejecutan en un contexto
de seguridad no especificado y en un contexto de transacciones no especificado. Durante la inicialización, la instancia se crea, se realiza la inclusión
de la dependencia, y se invocan las devoluciones de llamada del interceptor de
ciclo de vida PostConstruct. Las devoluciones de llamada del interceptor de ciclo de vida PreDestroy se
invocan para un bean de sesión con estado cuando se llama a un método remove.
Tenga en cuenta también que no
se invocan las devoluciones de llamadas del interceptor de ciclo de vida PreDestroy si el bean de sesión con
estado supera el tiempo de espera mientras está en estado pasivo o si se produce una excepción imprevista
durante una invocación de método del bean y el bean se descarta.
- Utilice los métodos PrePassivate y PostActivate si el bean de sesión con estado puede contener estado
que no es serializable. El contenedor puede desactivar una instancia de bean de sesión con estado siempre que
no esté incluida en una transacción o esté ejecutando actualmente una solicitud de método.
La instancia de
bean de sesión con estado se mueve al estado pasivo serializando todos los datos de estado. Si cualquiera de
los datos de estado no se serializan, el contenedor descarta la instancia de bean de sesión con estado.
- Considere la implementación de la interfaz sessionsynchronization opcional si los datos de estado del
bean de sesión con estado se han de restablecer después de una retrotracción de la transacción. Los datos de
estado de un bean de sesión con estado no son transaccionales y no se restablecen automáticamente en el estado
inicial como resultado de una retrotracción de la transacción. Al implementar el método afterCompletion de la
interfaz sessionsynchronization, la instancia de bean de sesión con estado se puede restablecer al estado
inicial o coherente.
- Utilice la anotación @accesstimeout para prohibir solicitudes de cliente simultáneas o para limitar el
tiempo que un método espera a que se le conceda el bloqueo de la instancia. De forma predeterminada, el
contenedor permite solicitudes de cliente simultáneas, pero serializa todas las llamadas al método y las
devoluciones de llamadas invocadas por el contenedor para impedir que múltiples hebras accedan a la instancia
del bean de sesión con estado.
Este comportamiento es similar al uso de la simultaneidad gestionada por contenedor con bloqueos de grabación
para beans de sesión singleton. No obstante, a diferencia de los beans de sesión singleton, los beans de
sesión con estado no se puede configurar para que utilicen la simultaneidad gestionada por beans y el tipo de
bloqueo no se puede cambiar. Sólo se puede modificar el valor de tiempo de espera de acceso para beans de
sesión con estado. El siguiente ejemplo de código ilustra un bean de sesión con estado con un valor de tiempo de espera de
acceso simultáneo que prohíbe las solicitudes de cliente simultáneas:
package com.ibm.example;
@Stateful
public class ShoppingCartBean implements ShoppingCart {
private ArrayList contents = new ArrayList();
@AccessTimeout( value=0 )
public void addToCart (Object o) {
contents.add(o);
}
public Collection getContents() {
return contents;
}
}
package com.ibm.example;
@Stateful
public class ShoppingCartBean implements ShoppingCart {
private ArrayList contents = new ArrayList();
@AccessTimeout( value=0 )
public void addToCart (Object o) {
contents.add(o);
}
public Collection getContents() {
return contents;
}
}
Si no se proporciona ninguna anotación, el comportamiento predeterminado es esperar a que se otorgue el
bloqueo. No existe límite en el tiempo que espera un cliente a que se otorgue el bloqueo. Como no se ha
especificado ningún valor a nivel de clase, no hay límite de tiempo de espera en la concesión de bloqueos
para todos los métodos de la clase. Si se utiliza la anotación @AccessTimeout y el contenedor no puede otorgar el bloqueo dentro del límite de
tiempo especificado, se emite una excepción javax.ejb.ConcurrentAccessTimeoutException en el cliente. La
anotación @AccessTimeout sólo se aplica a los métodos declarados en la misma clase en la que está la
anotación @AccessTimeout. Para una determinada clase, los metadatos de la anotación @AccessTimeout nunca se
heredan de una clase que esté por encima en el árbol de herencia de clase.
Un valor de tiempo de espera de acceso de-1 indica que las llamadas simultáneas al método bloquean el
acceso a
la instancia de bean indefinidamente (el valor predeterminado). Un valor de tiempo de espera de acceso de 0
indica que no se permiten las llamadas simultáneas al método. La excepción,
javax.ejb.ConcurrentAccessException,
se produce cuando se detecta la simultaneidad. Y cualquier valor positivo indica la cantidad de tiempo que se
ha de esperar
hasta que el método pueda continuar.
Antes de Java™ EE 6, el único comportamiento de simultaneidad
soportado
para los beans de sesión era un tiempo de espera de acceso de -1, no de simultaneidad. Dado que la
especificación Java EE 6 ha modificado el comportamiento
predeterminado, se da soporte a una propiedad del sistema que proporciona el comportamiento predeterminado
anterior. Consulte las propiedades del sistema EJB para obtener más información acerca de la propiedad del
sistema com.ibm.websphere.ejbcontainer.EE5Compatibility.
También puede especificar la anotación
@AccessTimeout utilizando el descriptor de despliegue XML y, si utiliza el descriptor de despliegue XML, los
metadatos de la anotación @AccessTimeout se ignoran. En el ejemplo siguiente se utiliza el descriptor de despliegue XML para especificar los mismos metadatos que en el ejemplo anterior.
<session>
<ejb-name>ShoppingCartBean</ejb-name>
<concurrent-method>
<method>
<method-name>addToCart</method-name>
</method>
<access-timeout>
<timeout>0</timeout>
<unit>Milliseconds</unit>
</access-timeout>
</concurrent-method>
</session>
- Es importante saber que el código XML de concurrent-methodType sigue los tres estilos descritos en la especificación EJB para componer el XML para los elementos del método container-transaction. Los tres estilos son: El estilo 1 utiliza el nombre de método especial * para aplicar el
tiempo de espera de acceso a todos los métodos de negocio para el bean
especificado.
<!-- Ejemplo: Estilo 1 -->
<concurrent-method>
<method>
<method-name>*</method-name>
</method>
<access-timeout>
<timeout>2000</timeout>
<unit>Milliseconds</unit>
</access-timeout>
</concurrent-method>
El estilo 2 se utiliza para hacer referencia a un método de negocio con un
nombre específico y asignarle el valor de tiempo de espera de acceso especificado. Si el nombre del método
está sobrecargado, lo que significa que varios métodos tienen el mismo nombre pero diferentes firmas de
método, todos los métodos con este nombre tienen el valor de tiempo de
espera especificado.
<!-- Ejemplo: Estilo 2 -->
<concurrent-method>
<method>
<method-name>businessMethod</method-name>
</method>
<access-timeout>
<timeout>2000</timeout>
<unit>Milliseconds</unit>
</access-timeout>
</concurrent-method>
El estilo 3 se utiliza para hacer referencia a un método distinto que coincide con el nombre del método
dado y tiene una firma de método que coincide con los parámetros de método listados. El estilo 3 tiene prioridad tanto sobre el estilo 1 como sobre el estilo 2.
<!-- Ejemplo: Estilo 3 -->
<concurrent-method>
<method>
<method-name>businessMethod</method-name>
<method-params>
<method-param>long</method-param>
<method-param>int</method-param>
</method-params>
</method>
<access-timeout>
<timeout>2000</timeout>
<unit>Milliseconds</unit>
</access-timeout>
</concurrent-method>
Si el XML del estilo 1 se utiliza para definir un tiempo de espera de acceso, todas las anotaciones
@AccessTimeout del bean se ignoran porque en su lugar se utiliza el nivel de método uno.
- Asegúrese de que comprende las reglas de herencia de las anotaciones que ha utilizado.
- Los beans de sesión no son de reentrada, lo que significa que el método de bean de sesión con
estado
se vuelve a llamar. Si se realiza una llamada de reentrada a un bean de sesión con estado, se produce una
excepción javax.ejb.ConcurrentAccessTimeoutException
en el cliente, independientemente del valor de tiempo de espera de acceso.
Esta excepción no da como resultado que se descarte el bean de sesión con estado ni marca la transacción para
su retrotracción, a menos que la excepción no la maneje el llamante.