410013796724260
• Webmoney
R335386147728
Z369087728698
JMS сообщения в Java приложенииJMS (Java Message Service) является стандартом обмена сообщениями между приложениями. Java приложения, выполненные по технологии Java SE (standalone) или Java EE (WEB) могут создавать, отправлять и получать JMS сообщения. Программное обеспечение, используемое для передачи сообщений между приложениями по стандарту JMS, формирует очереди сообщений queue. Отправка сообщений java-приложениями выполняется в асинхронном режиме, т.е. процедура не ждет ответа от получателя. В качестве получателей сообщений, организующих очереди (queue), может быть либо программное обеспечение типа WebSphere MQ, связывающее приложения через канал обмена сообщениями, либо WEB-контейнер типа JBoss, GlassFish, обеспечивающих обмен сообщениями между приложениями контейнера, либо по каналам Интернета с использованием JNDI. Получение сообщений java-приложением осуществляется либо по «подписке» (технология «издатель-подписчик»), либо из очереди («точка-точка»). Для получения сообщений по подписке необходимо должным образом подключиться к соответствующей очереди. При появлении в очереди сообщений они отправляются всем подписчикам. В модели «точка-точка» для получения сообщений необходимо периодически подключаться к соответствующей очереди и читать в ней сообщения. В статье рассматриваются примеры отправки и получения сообщений с использованием как WEB-приложения (Java EE), так standalone приложения (Java SE). Описание примеров разделено на две части. На этой странице рассматривается взаимодействие WEB-приложения с провайдером HornetQ. Взаимодействие standalone Java приложения с Websphere MQ рассматривается здесь. Пример обмена сообщения с сервером JBossВ первом простейшем WEB-приложении «jms-jboss» для отправки и получения JMS сообщений в качестве контейнера будет использован сервер приложений Wildfly версии 8.2 (ранее JBoss Application Server или JBoss AS). Настройка сервера приложений WildflyЧтобы использовать Wildfly для обмена сообщениями JMS необходимо настроить его файл конфигурации {WILDFLY_INSTALL_DIR}/standalone/configuration/standalone.xml. По умолчанию настройки JMS не включены в конфигурационный файл и их нужно определить вручную. Но можно использовать файл конфигурации standalone-full.xml, в котором сервер включает настройки JMS провайдера HornetQ, обеспечивающего создание соответствующих очередей и обмен сообщениями. В файл конфигурации standalone-full.xml в раздел <hornetq-server> секции <subsystem xmlns="urn:jboss:domain:messaging:2.0"> добавим очередь. Две очереди (ExpiryQueue и DLQ) уже имеются в подразделе <jms-destinations>. Добавим свою очередь testQueue с JNDI 'jms/queue/test' : <subsystem xmlns="urn:jboss:domain:messaging:2.0"> <hornetq-server> ... <jms-destinations> <jms-queue name="ExpiryQueue"> <entry name="java:/jms/queue/ExpiryQueue"/> </jms-queue> <jms-queue name="DLQ"> <entry name="java:/jms/queue/DLQ"/> </jms-queue> <jms-queue name="testQueue"> <entry name="jms/queue/test"/> <entry name="java:jboss/exported/jms/queue/test"/> </jms-queue> </jms-destinations> </hornetq-server> </subsystem> Для примера достаточно было добавить один элемент '<entry name="jms/queue/test"/>', который работает внутри контейнера. Второй элемент "java:jboss/exported/jms/queue/test" может работать за пределами контейнера, т.е. из другой JVM. Для него обязательным условием является определение в начале наименования "java:jboss/exported/". Можно было бы конечно использовать и существующие очереди (ExpiryQueue и DLQ).
Примечание : Чтобы стартовать Wildfly с файлом конфигурации standalone-full.xml из IDE Eclipse необходимо открыть окно 'JBoss Runtime' и определить значение 'Configuration file'. Для этого откройте вкладку Servers (Perspective 'Java EE') и дважды щелкните мышью на сервере Wildfly. В открывшемся окне Overview нажмите на ссылку 'Runtime Enviroment', в результате чего будет открыто окно 'JBoss Runtime' : Для запуска сервера приложений Wildfly не из IDE Eclipse c конфигурационным файлом standalone-full.xml можно использовать командный файл, в котором определить файл в качестве параметра : ./standalone.sh -c standalone-full.xml В конце страницы приведен Log сервера Wildfly, в котором показано создание соответствующих очередей и подключение MDB-объекта приложения к адаптеру HornetQ для получения JMS сообщений по подписке. Описание примераНа следующем скриншоте приведена структура WEB-приложения jms-jboss, включающего :
Проект в среде IDE Eclipse с использованием maven представлен на следующем скриншоте. Листинг сервлета ServiceServletСервлет ServiceServlet вызывается со страницы index.jsp из браузера с использованием jQuery. В качестве параметров сервлет получает 'prefix' сообщения и команду 'mode'. Для отправки JMS сообщения сервлет использует метод sendMessage класса Sender. Отправленные сообщения сервер Wildfly сразу же возвращает подписчику Receiver. Полученные сообщения сервлет читает из статической коллекции Receiver.messages, после чего очищает её. Отправленные и полученные сообщения сервлет оформляет в виде HTML-кода и возвращает в браузер. package org.jms.example; import java.io.IOException; import java.io.PrintWriter; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServiceServlet extends HttpServlet { private static final long serialVersionUID = 1L; @Inject Sender sender; private final String BR = "<br />"; @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String mode = request.getParameter("mode" ); String prefix = request.getParameter("prefix"); if(prefix == null || "".equals(prefix)) prefix = "prefix"; response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); if (mode.equalsIgnoreCase("send")) { out.print("send messages :" + BR); for (int i = 0; i < 3; i++) { String msg = prefix + " #" + i; out.print("• " + msg + BR); sender.sendMessage(msg); } out.close(); } else { out.print("receive messages :" + BR); if (Receiver.messages.size() > 0) { for (int i=0; i<Receiver.messages.size(); i++) { out.print("— " + Receiver.messages.get(i) + BR); } Receiver.messages.clear(); } out.close(); } } } Листинг дескриптора приложения, web.xmlВ дескрипторе приложения web.xml описывается сервлет ServiceServlet и его URL (url-pattern) для вызова, а также открываемая по умолчанию страница приложения. <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <display-name>JMS Application</display-name> <servlet> <servlet-name>JMSServlet</servlet-name> <servlet-class>org.jms.example.ServiceServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>JMSServlet</servlet-name> <url-pattern>/service</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> Листинг класса отправителя сообщений SenderКласс отправителя создается и «живет» вместе с WEB-приложением согласно аннотации @ApplicationScoped. При инсталляции сразу же определяются context и очередь queue. Сервлет отправляет текстовые сообщения, вызывая метод sendMessage. package org.jms.example; import javax.annotation.Resource; import javax.inject.Inject; import javax.jms.Queue; import javax.jms.JMSContext; import javax.enterprise.context.ApplicationScoped; @ApplicationScoped public class Sender { @Resource(mappedName = "jms/queue/test") private Queue queue; @Inject private JMSContext context; public void sendMessage(String txt) { context.createProducer().send(queue, txt); } } Листинг получателя сообщений ReceiverЗдесь следует несколько слов сказать о MDB (Message Driven Beans). Объект MDB используется для поддержки асинхронных коммуникаций в приложении, как правило, в сочетании с очередями. Клиент посылает сообщение в очередь, а MDB объект получает эти сообщения из очереди по подписке. Клиент не может вызывать MDB напрямую, связь обеспечивается с помощью сообщений JMS. MDB никогда не отвечает клиенту. Класс получателя сообщений оформлен как MDB объект с использованием аннотации, в которой определен ряд параметров, включающий JNDI очереди 'jms/queue/test'. Получатель реализует интерфейс javax.jms.MessageListener, согласно которому переопределяет метод onMessage. При появлении в очереди 'jms/queue/test' сообщения сервер приложений Wildfly сразу же вызовет метод onMessage данного MDB-объекта и передаст ему в качестве параметра сообщение javax.jms.Message, текст которого будет сохранен в коллекции messages. Сервлет имеет прямой доступ к набору полученных сообщений messages с модификаторами public и static. package org.jms.example; import java.util.List; import java.util.ArrayList; import java.util.logging.Level; import java.util.logging.Logger; import javax.jms.Message; import javax.jms.JMSException; import javax.jms.MessageListener; import javax.ejb.MessageDriven; import javax.ejb.ActivationConfigProperty; @MessageDriven(name = "Receiver", activationConfig = { @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "jms/queue/test"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") }) public class Receiver implements MessageListener { private Logger LOG = Logger.getLogger(Receiver.class.getName()); public static List<String> messages = new ArrayList<String>(); @Override public void onMessage(Message rcvMessage) { try { messages.add(rcvMessage.getBody(String.class)); } catch (JMSException ex) { LOG.log(Level.SEVERE, ex.getMessage(), ex); } } } Листинг страницы index.jspНа странице index.jsp определена библиотека jquery-3.2.1.min.js и JavaScript методы, которые используются для ajax-вызова сервлета. Интерфейс страницы включает текстовое поле 'prefix' и кнопки 'Отправить' и 'Получить'. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JMS пример</title> <script src="js/jquery-3.2.1.min.js" type="text/javascript"></script> <script> function sendMessages() { $.ajax({ url : 'service', data : { mode : 'send', prefix: document.getElementById('prefix').value }, success : function(response) { $('#sendJMS').html(response); } }); } function receiveMessages() { $.ajax({ url : 'service', data : { mode : 'receive' }, success : function(response) { $('#receiveJMS').html(response); } }); } </script> </head> <body> <h2>Пример JMS с использованием JBoss</h2> <p>Отправьте сообщения JBoss с префиксом <input id="prefix" type="text" size="5"></p> <input type="submit" width="80" value="Отправить" onClick="sendMessages()"><p /> <span id="sendJMS" style="color: #3f48cc;"> </span> <p>Получите сообщения из очереди JBoss</p> <input type="submit" width="80" value="Получить" onClick="receiveMessages()"><p /> <span id="receiveJMS" style="color: #7349a4;"> </span> </body> </html> Интерфейс страницы в браузере представлен на следующем скриншоте. При нажатии на кнопку 'Отправить' вызывается JavaScript процедура sendMessages, определяющая значения параметров (mode, prefix) и вызывающая сервлет для отправки сообщений. Результат выполнения команды в виде набора сообщений, оформленных в HTML-коде, возвращается в функцию success, которая выкладывает его в поле sendJMS на странице. Если префикс не определен, то сервлет будет использовать по умолчанию значение 'prefix'. Как только сообщения попадут в очередь сервер вернет их объекту 'Receiver' по подписке. При нажатии на кнопку 'Получить' вызывается JavaScript процедура receiveMessages, определяющая значение параметры mode и вызывающая сервлет для чтения полученных по подписке сообщений. Результат выполнения команды в виде набора сообщений, оформленных в HTML-коде, возвращается в функцию success, которая выкладывает его в поле receiveJMS на странице. Старт сервера WildflyСервер приложений Wildfly «логирует» всю информацию. При старте из IDE Eclipse эта информация дополнительно выводится в консоль. Ниже представлена информация (в сокращенном виде), связанная с настройкой сервером JMS очередей и стартом приложения «jms-jboss». В предпоследней строке отображено подключение MDB (Message Driven Bean) 'Receiver' к провайдеру HornetQ. [org.hornetq.core.server] Server is now live [org.hornetq.core.server] HornetQ Server version 2.4.5.FINAL [org.hornetq.core.server] trying to deploy queue jms.queue.ExpiryQueue [org.jboss.as.messaging] Bound messaging object to jndi name java:/jms/queue/ExpiryQueue [org.hornetq.ra] HornetQ resource adaptor started [org.jboss.as.messaging] Bound messaging object to jndi name java:jboss/DefaultJMSConnectionFactory [org.jboss.as.messaging] Bound messaging object to jndi name java:jboss/exported/jms/RemoteConnectionFactory [org.jboss.as.messaging] Bound messaging object to jndi name java:/ConnectionFactory [org.hornetq.core.server] trying to deploy queue jms.queue.testQueue [org.jboss.as.messaging] Bound messaging object to jndi name java:jboss/exported/jms/queue/test [org.jboss.as.messaging] Bound messaging object to jndi name jms/queue/test [org.hornetq.core.server] trying to deploy queue jms.queue.DLQ [org.jboss.as.messaging] Bound messaging object to jndi name java:/jms/queue/DLQ [org.jboss.weld.deployer] Processing weld deployment jms-jboss.war [org.jboss.as.ejb3] (MSC Started message driven bean 'Receiver' with 'hornetq-ra.rar' resource adapter [org.jboss.as.server] Deployed "jms-jboss.war" (runtime-name : "jms-jboss.war") Скачать примерИсходный код рассмотренного примера в виде проекта Eclipse с использованием Maven можно скачать здесь (994 Кб). Примеры взаимодействия Java приложения c Websphere MQ по отправки и чтению JMS сообщений представлены здесь. |