Desarrollo de beans de sesión singleton
Cree una clase de implementación de bean para un bean de sesión singleton, que se presenta en la especificación de Enterprise JavaBeans (EJB) 3.1. El contenedor EJB inicializa sólo una instancia de un bean de sesión singleton, y dicha instancia se comparte entre todos los clientes. Como una única instancia se comparte entre todos los clientes, los beans de sesión singleton tienen un ciclo de vida y una semántica de concurrencia especiales.
Antes de empezar
Acerca de esta tarea
public interface Configuration {
Object get(String name);
void set (String name, Object value);
}
@Singleton
public class ConfigurationBean implements Configuration {
private Map<String, Object> settings = new HashMap<String, Object>();
public Object get(String name) {
return settings.get(name);
}
public void set(String name, Object value) {
settings.put(name,value);
}
}
Al igual que con otros tipos de enterprise bean, también puede declarar metadatos para beans de sesión singleton 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>ConfigurationBean</ejb-name>
<business-local>com.ibm.example.Configuration</business-local>
<ejb-class>com.ibm.example.ConfigurationBean</ejb-class>
<session-type>Singleton</session-type>
</enterprise-beans>
</ejb-jar>
Procedimiento
- Codifique los métodos de inicialización y destrucción, comprendiendo
cómo se relacionan con las opciones para establecer el contexto de
transacciones. Durante la inicialización, la instancia se crea, se realiza la inclusión de la dependencia, y se inician las devoluciones de llamada del interceptor de
ciclo de vida PostConstruct. Las devoluciones de llamada del interceptor de
ciclo de vida PreDestroy se inician para un bean de sesión singleton cuando se
detiene la aplicación que contiene.
Puede resultar de utilidad completar las actividades transaccionales durante las devoluciones de llamada del interceptor de ciclo de vida PostConstruct y PreDestroy. Por este motivo, las devoluciones de llamada del interceptor de ciclo de vida del bean de sesión singleton tienen un contexto de transacción bien definido. Los valores del contexto de transacción siguientes son parecidos a los métodos @Timeout: sólo se pueden utilizar REQUIRED (valor predeterminado), REQUIRES_NEW y NOT_SUPPORTED, y REQUIRED se convierte en REQUIRES_NEW.
Los atributos de transacción sólo se reconocen cuando se especifican en los métodos de interceptor de ciclo de vida en la clase de bean. El mismo contexto de transacción se utiliza para todos los interceptores de ciclo de vida. El ejemplo siguiente ilustra un bean de sesión singleton con atributos de transacción especificados para las devoluciones de llamada del interceptor de ciclo de vida PostConstruct y PreDestroy.
@Singleton public class ConfigurationBean implements Configuration { @PostConstruct @TransactionAttribute(REQUIRED) // valor predeterminado; se especifica como ejemplo public void initialize() { // ... } @PreDestroy @TransactionAttribute(NOT_SUPPORTED) public void destroy() { // ... } // ... }
En lugar de utilizar una anotación, puede especificar los mismos metadatos utilizando el descriptor de despliegue XML. Si especifica atributos de transacción en el descriptor de despliegue XML, cualquier metadato obtenido de la anotación @TransactionAttribute se ignorará. En el ejemplo siguiente se utiliza el descriptor de despliegue XML para especificar los mismos metadatos que en el ejemplo anterior.
<assembly-descriptor> <container-transaction> <method> <ejb-name>ConfigurationBean</ejb-name> <method-name>initialize</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> <container-transaction> <method> <ejb-name>ConfigurationBean</ejb-name> <method-name>destroy</method-name> </method> <trans-attribute>NotSupported</trans-attribute> </container-transaction> </assembly-descriptor>
- A no ser que se especifique lo contrario, la instancia de bean de
sesión singleton se inicializa la primera vez que se utiliza el bean a través
de una de sus vistas de cliente, que es igual que cualquier otro bean de sesión. Utilice la anotación @Startup o el descriptor de despliegue XML correspondiente para marcar un bean como bean de arranque. Marcar un bean singleton como un bean de arranque implica que el contenedor EJB debe ejecutar antes el método PostConstruct para poder dar soporte a la ejecución de las solicitudes de clientes externos realizadas a la aplicación. Un método PostConstruct en un bean singleton puede crear un temporizador EJB, añadir un mensaje a una cola o tema JMS, llamar a un método EJB asíncrono o iniciar otros mecanismos asíncronos que llamen a un EJB. Sin embargo, para evitar un punto muerto, el método PostConstruct no debe esperar a que se ejecute un temporizador EJB, que se llame a un método de bean controlado por mensajes o que finalice un método EJB asíncrono.
Los desarrolladores de aplicaciones pueden colocar lógica empresarial en los métodos PostConstruct de estas instancias singleton de arranque para completar las tareas que deben realizarse antes de que el contenedor inicie ningún trabajo de cliente como, por ejemplo, precargar memorias caché o iniciar trabajo asíncrono dentro de la aplicación.
El ejemplo siguiente ilustra un bean de sesión singleton con inicialización de arranque:
@Singleton @Startup public class ConfigurationBean implements Configuration { @PostConstruct public void initialize() { // 1. Cree la tabla de base de datos si no existe. // 2. Inicialice valores de la tabla de base de datos. // 3. Cargue una memoria caché. // 4. Inicie trabajo asíncrono (por ejemplo, trabajo en una cola de mensajes o en // llamadas a métodos de bean de sesión asíncronos. } // ... }
En lugar de utilizar una anotación, puede especificar los mismos metadatos utilizando el descriptor de despliegue XML. Especifique true para marcar este bean singleton como un singleton de arranque. Por el contrario, especifique false, y la anotación @Startup se sustituye, si existe en el archivo de clase.
<session> <ejb-name>ConfigurationBean</ejb-name> <init-on-startup>true</init-on-startup> </session>
- Determine si el método de inicialización del bean de sesión singleton tiene una dependencia implícita sobre otro bean de sesión singleton.
Si existe una dependencia implícita, utilice los metadatos de dependencia para hacer que la dependencia sea explícita. El contenedor garantiza que los beans singleton de dependencia se inicialicen antes de sus beans dependientes se inicialicen y que se destruyan después de que sus beans dependientes se hayan destruido. El ejemplo siguiente ilustra un bean de sesión singleton con metadatos de dependencia:
@Singleton public class DatabaseBean { @PostConstruct public void initialize() { // Crear tablas de base de datos. } } @Singleton @DependsOn({"DatabaseBean"}) public class ConfigurationBean implements Configuration { @PostConstruct public void initialize() { // Inicializar valores de una tabla de base de datos. } // ... }
Además, puede realizar dependencias entre módulos utilizando la sintaxis ejb-link module.jar#bean. Las dependencias circulares no están soportadas y pueden hacer que una aplicación falle.
En lugar de utilizar una anotación, puede especificar los mismos metadatos utilizando el descriptor de despliegue XML. Si especifica metadatos de dependencia en el descriptor de despliegue XML, los metadatos de la anotación @DependsOn se ignorarán.
<session> <ejb-name>ConfigurationBean</ejb-name> <depends-on> <ejb-name>DatabaseBean</ejb-name> </depends-on> </session>
- Decida si desea utilizar simultaneidad gestionada por contenedor o
simultaneidad gestionada por bean. Las anotaciones @Lock y
@AccessTimeout no son aplicables si se utiliza la simultaneidad gestionada por
bean.
Sólo puede implementar la anotación @ConcurrencyManagement en la clase de bean de sesión singleton. No puede utilizarse en la clase que amplía ni en ninguna clase por encima en el árbol de herencia de clase.
El ejemplo de código siguiente ilustra un singleton con simultaneidad gestionada por bean:@Singleton @ConcurrencyManagement(BEAN) public class ConfigurationBean implements Configuration { private Map<String, Object> settings = new HashMap<String, Object>(); synchronized public Object get(String name) { return settings.get(name); } synchronized public void set(String name, Object value) { settings.put(name, value); } }
En lugar de utilizar una anotación, puede especificar los mismos metadatos utilizando el descriptor de despliegue XML. Si los metadatos se especifican en el descriptor de despliegue XML y utilizando la anotación @ConcurrencyManagement, el valor debe coincidir o la aplicación fallará. En el ejemplo siguiente se utiliza el descriptor de despliegue XML para especificar los mismos metadatos que en el ejemplo anterior.
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrency-management-type>Bean</concurrency-management-type> </session>
El contenedor no realiza el bloqueo de cada método invocado. En su lugar, el bean es responsable de los bloqueos que se necesitan. En el ejemplo, el proveedor de beans ha elegido implementar los métodos utilizando la palabra clave synchronized. Esta acción está soportada para los beans de sesión singleton con simultaneidad gestionada por bean, pero no está soportada para otros tipos de componente EJB. No es necesario que el proveedor de beans utilice la palabra clave synchronized para proporcionar la simultaneidad. Por ejemplo, el proveedor de beans puede utilizar la clase java.util.concurrent.locks.ReentrantReadWriteLock que se encuentra en JDK 5 y posterior.
La semántica de bloqueo que requiere la especificación de EJB 3.1 para simultaneidad gestionada por contenedor es igual que el comportamiento de la clase java.util.concurrent.locks.ReentrantReadWriteLock class.
- Si utiliza simultaneidad gestionada por contenedor, utilice la
anotación @Lock para gestionar la simultaneidad de los métodos. El código de ejemplo siguiente ilustra un singleton con simultaneidad gestionada por contenedor.
@Singleton public class ConfigurationBean implements Configuration { private Map<String, Object> settings = new HashMap<String, Object>(); @Lock(READ) public Object get(String name) { return settings.get(name); } public void set(String name, Object value) { settings.put(name, value); } }
En lugar de utilizar una anotación, puede especificar los mismos metadatos utilizando el descriptor de despliegue XML. Si los metadatos se especifican en el descriptor de despliegue XML y en la anotación @Lock, los metadatos obtenidos de la anotación @Lock se ignorarán. En el ejemplo siguiente se utiliza el descriptor de despliegue XML para especificar los mismos metadatos que en el ejemplo anterior.
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>get</method-name> </method> <lock>Read</lock> </concurrent-method> </session>
El ejemplo también ilustra la anotación de un método con @Lock(READ) que indica que el contenedor necesita obtener un bloqueo de lectura cuando se inicia ese método. Cuando se anota un método con @Lock, se altera temporalmente la anotación @Lock especificada a nivel de clase. Si no hay ninguna anotación @Lock a nivel de clase, el valor predeterminado es un bloqueo de grabación. En el ejemplo, @Lock(READ) en el método altera temporalmente el bloqueo de grabación predeterminado a nivel de clase. Cuando un método no está anotado a nivel de método y no hay ninguna anotación a nivel de clase, el contenedor utiliza el valor predeterminado del bloqueo de grabación.
Como la mayoría de los métodos necesitan un bloqueo de lectura, utilice @Lock(READ) a nivel de clase para indicar que todos los métodos de negocio en esta clase necesitan que el contenedor obtenga un bloqueo de lectura. Para los métodos que necesiten un bloqueo de grabación, anote estos métodos con @Lock(WRITE) para mostrar que altera temporalmente el bloqueo de lectura especificado a nivel de clase.
El ejemplo siguiente ilustra esta técnica:
@Singleton @Lock(READ) public class ConfigurationBean implements Configuration { private Map<String, Object> settings = new HashMap<String, Object>(); public Object get(String name) { return settings.get(name); } @Lock(WRITE) public void set(String name, Object value) { settings.put(name, value); } }
La anotación @Lock sólo se aplica a los métodos declarados en la misma clase que la anotación @Lock. Para una determinada clase, los metadatos de @Lock nunca se heredan de una clase que esté por encima en el árbol de herencia de clase. En lugar de utilizar una anotación en el nivel de clase, los mismos metadatos se pueden especificar en el descriptor de despliegue XML utilizando el nombre de método especial *, que coincide con todos los métodos.
- Si utiliza simultaneidad gestionada por contenedor, utilice la
anotación @AccessTimeout para limitar el tiempo que debe esperar un método a
que se otorgue un bloqueo. El ejemplo de código siguiente ilustra tiempos de espera de acceso
simultáneo.
@Singleton public class ConfigurationBean implements Configuration { @Lock(READ) @AccessTimeout(1000) public Object get(String name) { // consultar la base de datos } public void set(String name, Object value) { // actualizar la base de datos } }
Si no se proporciona ninguna anotación, el método espera, de manera predeterminada, hasta que se otorgue el bloqueo. No existe límite de tiempo en la espera de 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.
Al igual que la anotación @Lock, 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>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>get</method-name> </method> <lock>Read</lock> <access-timeout> <timeout>1000</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.
Recuerde que tanto los elementos lock como access-timeout son opcionales. Los tres estilos se describen a continuación:
El estilo 1 utiliza el nombre de método especial * para aplicar el tipo de bloqueo, el valor de tiempo de espera de acceso o ambos a todos los métodos de negocio para el bean especificado.
<!-- Ejemplo: Estilo 1 --> <concurrent-method> <method> <method-name>*</method-name> </method> <lock>Read</lock> <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 tipo de bloqueo especificado, el valor de tiempo de espera de acceso o ambos. 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 tipo de bloqueo especificado, el valor de tiempo de espera de acceso o ambos. El estilo 2 tiene prioridad sobre el estilo 1.
<!-- Ejemplo: Estilo 2 --> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <lock>Read</lock> <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 específico 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> <lock>Read</lock> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method>
Si el XML del estilo 1 se utiliza para definir un tipo de bloqueo, todas las anotaciones @Lock del bean se ignoran. Lo mismo es válido para el tiempo de espera de acceso. Si el XML del estilo 1 se utiliza para definir un tiempo de espera de acceso, todas las anotaciones @AccessTimeout del bean se ignoran.
- Es importante comprender que las anotaciones @Lock y @AccessTimeout se tratan de forma independientemente entre sí, al igual que el código del descriptor de despliegue XML correspondiente a cada una de ellas.
La implementación de este concepto tiene varias ventajas. Esta separación de tipo de bloqueo y tiempo de espera de acceso ayuda a evitar que se afecte negativamente al código de aplicación de caja negra, ya que no es necesario conocer el tipo de bloqueo. Puede dejar de forma segura el valor de tipo de bloqueo y ajustar el valor de tiempo de espera de acceso para que se ajuste sólo a las necesidades de su entorno, y evitar así posibles situaciones de punto muerto u otros problemas de simultaneidad.
Considere un escenario en el que tenga una aplicación EJB proporcionada por un proveedor en ejecución y que exceda constantemente el tiempo de espera debido a la ralentización del sistema. No desea cambiar la lógica de bloqueo por temor a causar una situación de punto muerto, pero desea modificar el límite de tiempo de espera. Puede editar el descriptor de despliegue y especificar el valor de tiempo de espera de acceso que necesite para los métodos que desee modificar.En el ejemplo siguiente se muestra cómo especificar simplemente una anotación @Lock(READ) a nivel de método en la implementación del bean y utilizar el estilo 2 para componer XML para especificar el elemento access-timeout para que sea de 2.000 milisegundos, sin proporcionar el elemento lock opcional. El resultado es un método con un bloqueo de lectura que tiene un tiempo de espera de acceso de 2.000 milisegundos.
@Singleton public class ConfigurationBean implements Configuration { @Lock(READ) public Object businessMethod(long value) { // ... } // ... }
Del mismo modo, puede utilizar una anotación de bloqueo a nivel de clase y, a continuación, especificar el valor de tiempo de espera de acceso desea en XML utilizando el estilo 2, el estilo 3 o ambos tal como se muestra en el ejemplo siguiente.<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
@Singleton @Lock(READ) public class ConfigurationBean implements Configuration { public Object businessMethod(long value) { // ... } public Object businessMethod(long value, int i, Object value) { // ... } public Object businessMethod(long value, int i) { // ... } }
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> <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>8000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
El ejemplo de código anterior hace que todos los métodos denominados “businessMethod” tengan un tipo de bloqueo de lectura y un tiempo de espera de acceso de 2.000 milisegundos. La excepción es la única instancia del método “businessMethod” que tiene una firma de método en la que el primer parámetro es de tipo long y el segundo es de tipo int. Esta instancia del método “businessMethod” tiene un tipo de bloqueo de lectura, pero un tiempo de espera de acceso de 8.000 milisegundos.
El mismo principio se aplica cuando el XML del estilo 1 se utiliza para definir sólo un tipo de bloqueo, pero no un valor de tiempo de espera de acceso. Puede añadir un valor de tiempo de espera de acceso a un método o a métodos específicos utilizando el estilo 2, el estilo 3 o ambos para obtener un resultado de un tipo de bloqueo y un valor de tiempo de espera de acceso específicos. En el ejemplo siguiente se muestra esta cuestión:<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>*</method-name> </method> <lock>Read</lock> </concurrent-method> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
El ejemplo de código anterior hace que todos los métodos de negocio tengan un tipo de bloqueo de lectura y el método denominado businessMethod tenga un tipo de bloqueo de lectura y un tiempo de espera de acceso de 2.000 milisegundos.
También puede tener una anotación @Lock a nivel de clase para establecer el tipo de bloqueo para todos los métodos y utilizar el estilo 1 para componer XML para establecer sólo el valor de tiempo de espera de acceso para todos los métodos. Consulte el ejemplo siguiente:@Singleton @Lock(READ) public class ConfigurationBean implements Configuration { public Object businessMethod(long value) { // ... } // ... }
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>*</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
El ejemplo anterior hace que todos los métodos de negocio del bean ConfigurationBean tengan un tipo de bloqueo de lectura y un valor de tiempo de espera de acceso de 2.000 milisegundos.
- Asegúrese de que comprende las reglas de herencia de las anotaciones que ha utilizado.
- Evite el comportamiento de bloqueos de reentrada que puede producirse si un método de bloqueo de lectura llama a un método de bloqueo de
grabación en el mismo bean de sesión singleton.
Supongamos que el método de negocio de un bean de sesión singleton provoca el inicio directo o indirecto de otro método de negocio del bean de sesión singleton. Si el primer método es un método de bloqueo de grabación, ese método puede llamar a cualquier otro método de negocio del bean de sesión singleton sin ninguna consideración especial. No obstante, puede implementar con cuidado un método de bloqueo de lectura si desea invocar otro método de negocio de la misma clase de bean de sesión singleton que es un método de bloqueo de grabación. A continuación, se produce una excepción javax.ejb.IllegalLoopbackException.
Subtopics
Cambio de la política de bloqueo de bean de sesión singleton
Utilice esta tarea para alterar temporalmente la política de bloqueo no justo para todos los bloqueos de grabación de beans de sesión singleton dentro del servidor. Esta tarea es para los usuarios de WebSphere Application Server que no desean que sus solicitudes de bloqueo para las invocaciones del método de bean de sesión singleton que sigan una política de bloqueo no justa.Cambio de la política de bloqueo de bean de sesión singleton
Utilice esta tarea para alterar temporalmente la política de bloqueo no justo para todos los bloqueos de grabación de beans de sesión singleton dentro del servidor. Esta tarea es para los usuarios de WebSphere Application Server que no desean que sus solicitudes de bloqueo para las invocaciones del método de bean de sesión singleton que sigan una política de bloqueo no justa.


http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=tejb_ssb
File name: tejb_ssb.html