Diseño de aplicaciones de empresa para utilizar JMS
Deben tenerse en cuenta numerosos factores a la hora de diseñar aplicaciones de empresa de modo que utilicen las API JMS directamente para mensajes asíncronos.
Procedimiento
- Para operaciones de mensajes, puede escribir programas de
aplicación que utilizan sólo referencias a las interfaces definidas en
el paquetes javax.jms de Sun. JMS define una vista genérica de mensajes que establece una correlación en el transporte subyacente. Las aplicaciones de empresa que utilizan JMS emplean las interfaces siguientes que están definidas en el paquete javax.jms de Sun:
- Conexión
- Proporciona acceso al transporte subyacente y se utiliza para crear sesiones.
- Sesión
- Proporciona un contexto para producir y consumir mensajes, incluidos los métodos utilizados para crear MessageProducers y MessageConsumers.
- MessageProducer
- Se utiliza para enviar mensajes.
- MessageConsumer
- Se utiliza para recibir mensajes.
Las interfaces genéricas JMS se dividen en subclases en las versiones siguientes más específicas para el comportamiento punto a punto y de publicación/suscripción.Tabla 1. Versiones de punto a punto y publicación/suscripción de interfaces comunes de JMS. La primera columna de esta tabla lista interfaces comunes de JMS, la segunda columna lista las interfaces de punto a punto correspondientes y la tercera columna lista las interfaces de publicación/suscripción correspondientes. Interfaces comunes de JMS Interfaces de punto a punto Interfaces de publicación/suscripción ConnectionFactory QueueConnectionFactory TopicConnectionFactory Conexión QueueConnection TopicConnection Destination Cola Tema Sesión QueueSession, TopicSession, MessageProducer QueueSender TopicPublisher MessageConsumer QueueReceiver,
QueueBrowserTopicSubscriber Para obtener más información sobre cómo utilizar estas interfaces JMS, consulte la Documentación de servicio de mensajes Java™ y la sección Utilización de Java del centro de información de IBM MQ.
El apartado "Java Message Service (JMS) Requirements" (Requisitos de Java Message Service (JMS) de la J2EE specification (especificación de J2EE) ofrece una lista de métodos que no debe llamar en contenedores web y EJB:javax.jms.Session method setMessageListener javax.jms.Session method getMessageListener javax.jms.Session method run javax.jms.QueueConnection method createConnectionConsumer javax.jms.TopicConnection method createConnectionConsumer javax.jms.TopicConnection method createDurableConnectionConsumer javax.jms.MessageConsumer method getMessageListener javax.jms.MessageConsumer method setMessageListener javax.jms.Connection setExceptionListener javax.jms.Connection stop javax.jms.Connection setClientID
Esta restricción de método se aplica en WebSphere Application Server emitiendo una excepción javax.jms.IllegalStateException.
- Las aplicaciones hacen referencia a recursos JMS que son predefinidos, como los
objetos administrados, en WebSphere Application Server.
Las aplicaciones de empresa utilizan detalles de recursos JMS que se definen en WebSphere Application Server y se enlazan al espacio de nombres JNDI mediante el soporte administrativo de WebSphere. Las aplicaciones de empresa pueden recuperar estos objetos del espacio de nombres JNDI y utilizarlos sin necesidad de saber nada sobre su implementación. Esto permite que la arquitectura de mensajes subyacente definida mediante los recursos JMS se pueda cambiar sin necesidad de realizar cambios en la aplicación de empresa.
Tabla 2. Recursos JMS para mensajería punto a punto y publicación/suscripción. La primera columna de esta tabla lista los recursos JMS para la mensajería punto a punto, y la segunda columna lista los recursos JMS para la publicación/suscripción. Punto a punto Publicación/suscripción ConnectionFactory (o QueueConnectionFactory)
ColaConnectionFactory (o TopicConnectionFactory)
TemaUna fábrica de conexiones se utiliza para crear conexiones del proveedor de JMS al sistema de mensajería y encapsula los parámetros de configuración necesarios para crear las conexiones.
- El servidor de aplicaciones agrupa conexiones y sesiones con el proveedor de JMS para mejorar el rendimiento. Debe configurar las propiedades de agrupación de sesiones y conexiones para las aplicaciones adecuadamente; de lo contrario, es posible que no obtenga el comportamiento de sesión o conexión deseado.
- Las aplicaciones no deben almacenar en memoria caché conexiones JMS,
sesiones y productores o consumidores. WebSphere Application
Server cierra estos objetos cuando un bean o servlet finaliza y, por lo tanto, cualquier intento
de utilizar un objeto almacenado en memoria caché fallará con una excepción javax.jms.IllegalStateException.
Para mejorar el rendimiento, las aplicaciones pueden almacenar en memoria caché los objetos JMS que se han buscado en JNDI. Por ejemplo, un EJB o servlet necesita buscar sólo una vez una fábrica de conexiones JMS, pero debe llamar al método createConnection en cada instancia. Debido al efecto de agrupación de conexiones y sesiones con el proveedor de JMS, no debería haber ningún impacto en el rendimiento.
- Un suscriptor no duradero sólo se puede utilizar en el mismo contexto transaccional (por ejemplo, una transacción global o un contexto de transacción sin especificar) que existía cuando se creó la suscripción.
- Utilización de las suscripciones durables con el proveedor de mensajería predeterminado. Una suscripción durable en un tema de JMS habilita un suscriptor para
recibir una copia de todos los mensajes publicados en ese tema, incluso después
de períodos de tiempo cuando el suscriptor no está conectado al servidor. Por
lo tanto, las aplicaciones de suscriptor pueden funcionar desconectadas del
servidor durante largos períodos de tiempo y, a continuación, volverse a
conectar con el servidor y procesar mensajes que se han publicado durante su
ausencia.
Si una aplicación crea una suscripción durable, se añade a la lista de
módulos ejecutables que los administradores pueden visualizar y en los que
pueden actuar a través de la consola administrativa.
Se asigna a cada suscripción durable un identificador exclusivo, ID_cliente##nombre_sus donde:
- ID_cliente
- Identificador de cliente utilizado para asociar una conexión y sus objetos con los mensajes mantenidos para aplicaciones (como clientes del proveedor de JMS). Debe utilizar una convención de denominación que le ayude a identificar las aplicaciones, en caso de que tenga que relacionar suscripciones durables con las aplicaciones asociadas para administración de módulos ejecutables.
- nombre_sus
- El nombre de suscripción que se utiliza para identificar exclusivamente una suscripción durable dentro de un identificador de cliente determinado.
Para suscripciones durables creadas por beans controlados por mensajes, los valores se establecen en la especificación de activation de JSM. Para otras suscripciones durables, el identificador de cliente se establece en la fábrica de conexiones de JMS y el nombre de suscripción lo establece la aplicación en la operación createDurableSubscriber.
Para crear una suscripción durable a un tema, una aplicación utiliza la operación createDurableSubscriber definida en la API de JMS:public TopicSubscriber createDurableSubscriber(Topic topic, java.lang.String subName, java.lang.String messageSelector, boolean noLocal) throws JMSException
- topic
- Nombre del tema de JMS al que se debe suscribir. Es el nombre de un objeto que da soporte a las interfaces javax.jms.Topic, como las que se encuentran buscando una entrada JNDI adecuada.
- subName
- Nombre que se utiliza para identificar esta suscripción.
- messageSelector
- Sólo los mensajes con propiedades que coincidan con la expresión de selector de mensajes se entregan a los consumidores. Un valor nulo o una serie vacía indica que se deben entregar todos los mensajes.
- noLocal
- Si se establece en true, este parámetro evita la entrega de los mensajes publicados en la misma conexión que el suscriptor durable.
Las aplicaciones puede utilizar un formulario de dos argumentos de createDurableSubscriber que adopte sólo los parámetros topic y subName. Esta llamada alternativa invoca de forma directa la versión de cuatro argumentos, como se ha mostrado antes, pero establece messageSelector en null (para que se entreguen todos los mensajes) y establece noLocal en false (se entregan los mensajes publicados en la conexión). Por ejemplo, para crear una suscripción durable al tema denominado myTopic, con el nombre de suscripción mySubscription:session.createDurableSubscriber(myTopic,"mySubscription");
Si la operación createDurableSubscription falla, genera una excepción de JMS que proporciona un mensaje y una excepción enlazada para dar información más detallada sobre la causa del problema.
Para suprimir una suscripción durable, una aplicación utiliza la operación de anulación de suscripción definida en la API de JMS.
En funcionamiento normal, puede haber, como máximo, un suscriptor activo (conectado) para una suscripción durable a la vez. No obstante, la aplicación de suscriptor puede ejecutarse en un servidor de aplicaciones clonado con fines de sustitución por anomalía y equilibrio de cargas. En tal caso, la restricción de "un suscriptor activo" se eleva para proporcionar una suscripción durable compartida que pueda tener varios consumidores simultáneos.
Para obtener más información sobre el uso por parte de la aplicación de suscripciones durables, consulte el apartado "Utilización de suscripciones durables" en la especificación de JMS.
- Determine qué selectores de mensajes son necesarios. Puede utilizar el método selector de mensajes de JMS para seleccionar un subconjunto de los mensajes en cola para que una cola de recepción devuelva este subconjunto. El selector puede hacer referencia a campos de la cabecera del mensaje JMS y a campos de las propiedades del mensaje.
- Actuación sobre los mensajes recibidos. Cuando se recibe un mensaje, puede actuar sobre éste como sea necesario mediante la lógica empresarial de la
aplicación. Algunas acciones de JMS generales son comprobar que el mensaje es
del tipo correcto y extraer el contenido del mensaje. Para extraer el contenido
del cuerpo del mensaje, debe realizar la conversión de tipos de la clase
Message genérica (que es el tipo de devolución declarado de los métodos
receive) a la subclase más específica, como TextMessage. Es un buen sistema probar siempre
la clase message antes de convertir, de este modo los errores inesperados se pueden
tratar más fácilmente.
En este ejemplo, se utiliza la instancia de operador instanceof para comprobar que el mensaje recibido es del tipo instanceof. Luego se extrae el contenido del mensaje convirtiendo su tipo a la subclase TextMessage.
if ( inMessage instanceof TextMessage ) ... String replyString = ((TextMessage) inMessage).getText();
- Las aplicaciones de JMS que utilizan el proveedor de mensajería pueden acceder, sin restricciones, al contenido de los mensajes que se han recibido de la mensajería incorporada de WebSphere Application Server versión 5 o IBM MQ.
- Las aplicaciones de JMS pueden acceder al conjunto completo de propiedades JMS_IBM*. Estas propiedades son valiosas para las aplicaciones de JMS que utilizan
recursos proporcionados por el proveedor de mensajería predeterminado, el
proveedor de mensajería predeterminado de la V5 o el proveedor de IBM MQ.
Para los mensajes gestionados por IBM MQ, las propiedades JMS_IBM* se correlacionan con los campos de IBM MQ Message Descriptor (MQMD). Para obtener más información acerca de las propiedades JMS_IBM* y los campos MQMD, consulte la sección Utilización de Java del Information Center de IBM MQ.
- Las aplicaciones de JMS pueden utilizar mensajes de informe como forma de proceso de solicitudes/respuestas gestionado para proporcionar información remota a los productores sobre el resultado de sus operaciones de envío y el destino de sus mensajes. Las aplicaciones de JMS pueden solicitar una amplia gama de opciones de informe con las propiedades de mensajes JMS_IBM_Report_Xxxx. Para obtener más información sobre la utilización de mensajes de informe de JMS, consulte Mensajes de informes JMS.
- Las aplicaciones de JMS pueden utilizar la propiedad
JMS_IBM_Report_Discard_Msg para controlar cómo se elimina un mensaje de
petición o si no se puede entregar a la cola de destino.
- MQRO_Dead_Letter_Queue
- Es el valor predeterminado. El mensaje de solicitud debe escribirse en la cola de cartas finalizada.
- MQRO_Discard
- El mensaje de solicitud debe descartarse. Se utiliza normalmente junto con MQRO_Exception_With_Full_Data para devolver un mensaje de solicitud no entregable a su emisor.
- Utilización de una escucha para recibir mensajes de forma asíncrona. En un cliente, no en un servlet o enterprise bean, una alternativa para realizar
llamadas a QueueReceiver.receive() es registrar un método que se llame
automáticamente cuando esté disponible un mensaje adecuado, por ejemplo:
... MyClass listener =new MyClass(); queueReceiver.setMessageListener(listener); //la aplicación continua con otro comportamiento específico de la aplicación. ...
Cuando está disponible un mensaje, se recupera mediante el método onMessage() en el objeto de escucha.import javax.jms.*; public class MyClass implements MessageListener { public void onMessage(Message message) { System.out.println("message is "+message); //a continuación, el proceso específico de la aplicación ... } }
Para la entrega de mensajes asíncronos, el código de aplicación no puede capturar excepciones activados por anomalías al recibir mensajes. Esto se debe a que el código de aplicación no realiza llamadas explícitas a métodos receive(). Para hacer frente a esta situación, puede registrar un ExceptionListener, que es una instancia de una clase que implementa el método onException(). Cuando se produce un error, se llama a este método con la excepción JMSException como su único parámetro.
Para obtener más detalles sobre el uso de escuchas para recibir mensajes de forma asíncrona, consulte la Documentación de Java Message Service.
Nota: Como alternativa a desarrollar su propia clase de escucha JMS, puede utilizar beans controlados por mensajes, como se describe en el apartado Programación que utiliza beans controlados por mensajes. Tenga cuidado cuando ejecute JMS receive() desde un componente de aplicación del lado del servidor si esa invocación de receive() espera en un mensaje producido por otro componente de aplicación desplegado en el mismo servidor. Dicho JMS receive() es síncrono, por lo que se bloquea hasta que se recibe el mensaje de respuesta.
Este tipo de diseño de aplicación puede conducir a un problema del consumidor o el productor en el que el componente receptor, cuya espera de respuestas se ha bloqueado, puede agotar el conjunto entero de hebras de trabajo, con lo que no quedan hebras de trabajo disponibles a las que asignar el componente de la aplicación que generaría el mensaje JMS de respuesta. Por ejemplo, un servlet y un bean controlado por mensajes están desplegados en el mismo servidor. Cuando el servlet asigna una solicitud, envía un mensaje a una cola que recibe servicio del bean controlado por mensaje (esto es, los mensajes producidos por el servlet son consumidos por el método onMessage() del bean controlado por mensaje). A continuación, el servlet emite receive(), esperando una respuesta en la cola temporal ReplyTo. El método onMessage() de bean controlado por mensaje realiza una consulta a la base de datos y devuelve una respuesta al servlet en la cola temporal. Si se produce al mismo tiempo un gran número de solicitudes de servlet (respecto al número de hebras de trabajo del servidor), es probable que todas las hebras de trabajo del servidor disponibles se utilicen para enviar una respuesta de servlet, enviar un mensaje y esperar una respuesta. A continuación, el servidor de aplicaciones entra en un estado en el que no queda ninguna hebra para procesar de los beans controlados por mensaje que ahora están pendientes. Por lo tanto, como las respuestas que los servlets están esperando están todas bloqueadas, el servidor se cuelga, lo que probablemente genere una anomalía de la aplicación.
Las soluciones posibles son:
- Asegúrese de que el número de hebras de trabajo (# de hebras por región de servidor * # de regiones de servidor por servidor) es mayor que el número de asignaciones simultáneas del componente de aplicación que ejecuta receive(), para que haya siempre una hebra de trabajo disponible para el componente que produce el mensaje.
- Utilice una topología de aplicación que coloque el componente de aplicación receptor en un servidor distinto al del componente de aplicación productor. Aunque el uso de hebras de trabajo se debe controlar con cuidado también en este tipo de escenario de despliegue, esta separación garantiza que siempre haya hebras que no se puedan bloquear por el componente de recepción de mensajes. Hay otras interacciones que se deben tener en cuenta, como el caso de un servidor de aplicaciones que tenga varias aplicaciones instaladas.
- Vuelva a factorizar la aplicación para que realice las recepciones de mensajes desde un componente de cliente, para que no compita por hebras de trabajo con el componente productor. Además, el componente de cliente puede realizar recepciones asíncronas (sin bloqueo), que están prohibidas por los servidores J2EE. Según esto, la aplicación de ejemplo anterior puede refactorizarse para que tenga un cliente que envíe mensajes a una cola y espere la respuesta del MDB.
- Si desea utilizar la autenticación con IBM MQ o el soporte de mensajería incorporada predeterminado de la versión 5, no puede utilizar los ID de usuario que tengan más de 12 caracteres. Por ejemplo, el ID de usuario predeterminado de Windows NT, administrador, no es válido para utilizarlo con el servicio de mensajes interno de WebSphere, dado que contiene 13 caracteres.
- Los puntos siguientes, como se definen en la especificación de EJB, se aplican al
uso de distintivos en llamadas createxxxSession:
- El distintivo transacted que se pasa a createxxxSession se ignora dentro de transacciones globales y todo el trabajo se realiza como parte de la transacción. Fuera de las transacciones se utiliza el distintivo transacted y, si está establecido en true, la aplicación debería utilizar session.commit() y session.rollback() para controlar la finalización del trabajo. En módulos EJB2.0, si el distintivo transacted está establecido en true y fuera de una transacción XA, la sesión interviene en la transacción local de WebSphere y el atributo de acción sin resolver del método se aplica al trabajo de JMS si la aplicación no lo ha confirmado o retrotraído.
- Los clientes no pueden utilizar Message.acknowledge() para reconocer mensajes. Si se pasa un valor de CLIENT_ACKNOWLEDGE en la llamada a createxxxSession, se reconocerán automáticamente los mensajes en el servidor de aplicaciones y no se utilizará Message.acknowledge().
- Si desea que la aplicación utilice IBM MQ como proveedor de JMS externo, envíe los mensajes dentro de una transacción gestionada por contenedor.
Cuando utiliza IBM MQ como proveedor de JMS externo, los mensajes enviados dentro de una transacción gestionada por usuario pueden llegar antes de que se confirme la transacción. Esto se produce sólo cuando utiliza IBM MQ como proveedor de JMS externo y envía los mensajes a una cola de IBM MQ en una transacción gestionada por usuario. El mensaje llega a la cola de destino antes de que la transacción se confirme.
La causa de este problema es que el gestor de recursos de IBM MQ no figura en la transacción gestionada por el usuario.
La solución es utilizar una transacción gestionada por contenedor.


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