- Серія контенту:
- Цей контент є частиною серії: Поради з програмування Web-сервісів
- Шаблон асинхронного запиту
- Малюнок 1. Шаблон асинхронного запиту
- Проектування інтерфейсу сервісу
- Лістинг 1. AsyncService.wsdl
- Лістинг 2. Обмін повідомленнями AsyncService
- Лістинг 3. JNDIListenerServlet.java
- Лістинг 4. JNDIHelper.java
- Лістинг 5. AsyncService.java
- висновки
- Ресурси для скачування
Поради з програмування Web-сервісів
Асинхронні операції Web-сервісів з використанням JMS
Серія контенту:
Цей контент є частиною # з серії # статей: Поради з програмування Web-сервісів
https://www.ibm.com/developerworks/ru/library/?series_title_by=**auto**
Слідкуйте за виходом нових статей цієї серії.
Цей контент є частиною серії: Поради з програмування Web-сервісів
Слідкуйте за виходом нових статей цієї серії.
Якщо уявити собі реалізацію Web-сервісів з SOAP, швидше за все, вам прийдуть в голову прості синхронні операції типу запит-відповідь. Насправді Service-Oriented Architecture (SOA) може охоплювати набагато більший діапазон моделей обміну повідомленнями та стратегій проектування. В даному документі ми сфокусуємось на застосуванні основних шаблонів проектування Web-додатків з використанням Web-сервісів. Подані шаблони не є новими, вони використовуються в традиційних Web-додатках вже багато років, проте багато розробників навіть не підозрюють про те, як реалізувати такі методики в області Web-сервісів або ж не до кінця розуміють, як їх застосовувати. Автор ставить перед собою завдання уявлення набору простих, відкритих альтернатив проектування моделі запит-відповідь. Для вивчення прикладу вам необхідно мати хоча б основні уявлення про реалізацію Web-сервісів в середовищі J2EE.
Шаблон асинхронного запиту
Щоб відкинути зайве, ми досліджуємо реалізацію асинхронних операцій запитів і відповідей з метою розбиття тривалих операцій, і для того щоб уникнути тайм-аутів або довгих відбою при виконанні коду. Якщо ви маєте досвід реалізації асинхронних запитів в традиційних Web-додатках HTTP і HTML, застосовуваний шаблон повинен бути вам знаком.
Малюнок 1. Шаблон асинхронного запиту
Потік в даній моделі досить простий:
- Запитуюча Сторона передає запит до постачальника сервісу, той ставить повідомлення в чергу і повертає ID кореляції, який запитує, сторона пізніше може використовувати для перевірки статусу запиту.
- Оброблювач запиту видаляє запит з черги і обробляє його. Зазвичай обробка запиту є тривалим процесом. Після завершення обробки процесор ставить в чергу повідомлення відповіді.
- У певний невизначений момент часу, яка запитує сторона опитує постачальника сервісу на предмет готовності запиту. Якщо запит знаходиться в черзі, постачальник повертає його назад. Якщо запит недоступний, постачальник повідомляє про це запитуючої сторони, яка може вибрати - скасувати запит або чекати відповіді, опитуючи постачальника через певні проміжки часу на наявність готового запиту.
Про застосування даного шаблону в додатках сервлетів J2EE для Java Ranch (Web-сайту Java-розробників) написана чудова стаття, автором якої є Kyle Brown (Див. Ресурси по темі ). У даній статті, крім усього іншого, обговорюються мотивації і основні питання проектування щодо базової реалізації даного шаблону. Тож не дивно, що реалізація не сильно змінилася в шаблоні, застосовне для Web-сервісів.
Проектування інтерфейсу сервісу
Для ілюстрування шаблону асинхронного запиту ми реалізуємо простий приклад Web-сервісу, який поза цього прикладу не має особливого практичного значення. Даний сервіс виконує просте перетворення трьох вхідних значень типу String з нижнього регістра в верхній після застосування 10-ти секундної затримки (для симуляції тривалих процесів).
Для реалізації даного сервісу доступні дві операції: submitRequest і checkResponse. Дія цих операцій не вимагає пояснення. В лістингу 1 представлений WSDL, що описує інтерфейс сервісу.
Лістинг 1. AsyncService.wsdl
<? Xml version = "1.0" encoding = "UTF-8"?> <Wsdl: definitions targetNamespace = "http://one.wspattern.developerworks.ibm.com" xmlns: impl = "http: //one.wspattern .developerworks.ibm.com "xmlns: intf =" http://one.wspattern.developerworks.ibm.com "xmlns: wsdl =" http://schemas.xmlsoap.org/wsdl/ "xmlns: wsdlsoap =" http : //schemas.xmlsoap.org/wsdl/soap/ "xmlns: xsd =" http://www.w3.org/2001/XMLSchema "> <wsdl: types> <schema targetNamespace =" http: // one. wspattern.developerworks.ibm.com "xmlns =" http://www.w3.org/2001/XMLSchema "xmlns: impl =" http://one.wspattern.developerworks.ibm.com "xmlns: intf =" http : //one.wspattern.developerworks.ibm.com "xmlns: wsdl =" http://schemas.xmlsoap.org/wsdl/ "xmlns: xsd =" http://www.w3.org/2001/XMLSchema " > <complexType name = "ResponseCheck"> <sequence> <element name = "correlationID" nillable = "true" type = "xsd: string" /> </ sequence> </ complexType> <element name = "ResponseCheck" nillable = "true" type = "impl: ResponseCheck" /> <complexType name = "Response"> <sequence> <element name = "type" type = "xsd: int" / > <Element name = "correlationID" nillable = "true" type = "xsd: string" /> <element name = "refresh" type = "xsd: int" /> <element name = "a" nillable = "true" type = "xsd: string" /> <element name = "b" nillable = "true" type = "xsd: string" /> <element name = "c" nillable = "true" type = "xsd: string" / > </ sequence> </ complexType> <element name = "Response" nillable = "true" type = "impl: Response" /> <complexType name = "Request"> <sequence> <element name = "a" nillable = "true" type = "xsd: string" /> <element name = "b" nillable = "true" type = "xsd: string" /> <element name = "c" nillable = "true" type = "xsd: string "/> </ sequence> </ complexType> <element name =" Request "nillable =" true "type =" impl: Request "/> </ schema> </ wsdl: types> <wsdl: message name =" submitRequestRequest "> <wsdl: part name =" request "type =" intf: Request "/> </ wsdl: message> <wsdl: message name =" checkResponseResponse "> <wsdl: part name =" checkResponseReturn "type =" intf : Response "/> </ wsdl: message> <wsdl: message name =" checkResponseRequest "> <wsdl: part name =" check "type =" intf: ResponseCheck "/> </ Wsdl: message> <wsdl: message name = "submitRequestResponse"> <wsdl: part name = "submitRequestReturn" type = "intf: Response" /> </ wsdl: message> <wsdl: portType name = "AsyncService"> <wsdl: operation name = "checkResponse" parameterOrder = "check"> <wsdl: input message = "intf: checkResponseRequest" name = "checkResponseRequest" /> <wsdl: output message = "intf: checkResponseResponse" name = "checkResponseResponse" / > </ wsdl: operation> <wsdl: operation name = "submitRequest" parameterOrder = "request"> <wsdl: input message = "intf: submitRequestRequest" name = "submitRequestRequest" /> <wsdl: output message = "intf: submitRequestResponse "name =" submitRequestResponse "/> </ wsdl: operation> </ wsdl: portType> <wsdl: binding name =" AsyncServiceSoapBinding "type =" intf: AsyncService "> <wsdlsoap: binding style =" rpc "transport =" http : //schemas.xmlsoap.org/soap/http "/> <wsdl: operation name =" checkResponse "> <wsdlsoap: operation soapAction =" "/> <wsdl: input name =" checkResponseRequest "> <wsdlsoap: body namespace = "http://one.wspattern.developerworks.ibm .com "use =" literal "/> </ wsdl: input> <wsdl: output name =" checkResponseResponse "> <wsdlsoap: body namespace =" http://one.wspattern.developerworks.ibm.com "use =" literal "/> </ wsdl: output> </ wsdl: operation> <wsdl: operation name =" submitRequest "> <wsdlsoap: operation soapAction =" "/> <wsdl: input name =" submitRequestRequest "> <wsdlsoap: body namespace = "http://one.wspattern.developerworks.ibm.com" use = "literal" /> </ wsdl: input> <wsdl: output name = "submitRequestResponse"> <wsdlsoap: body namespace = "http: / /one.wspattern.developerworks.ibm.com "use =" literal "/> </ wsdl: output> </ wsdl: operation> </ wsdl: binding> <wsdl: service name =" AsyncServiceService "> <wsdl: port binding = "intf: AsyncServiceSoapBinding" name = "AsyncService"> <wsdlsoap: address location = "http: // localhost: 9080 / WSPattern1 / services / AsyncService" /> </ wsdl: port> </ wsdl: service> </ wsdl: definitions>Тут слід зазначити кілька моментів:
- Сервіс використовує стиль написання коду RPC / Literal.
- Обидві операції submitRequest і checkResponse повертають об'єкт з ім'ям Response. Існує два різновиди Response, що визначаються властивістю типу (type property). Значення властивості типу рівне 0 вказує на Refresh Response, а значення 1 - на Request Response. Refresh Response вказує на те, що відповідь ще не доступний і яка запитує сторона повинна підтвердити нову операцію checkResponse не раніше, ніж зазначено в значенні властивості поновлення (еквівалентно механізму HTTP META Refresh, обговорюваного в статті Kyle Brown). Request Response містить три рядки введення в верхньому регістрі і представляє завершення обробки запиту.
- Refresh Response містить властивість Correlation ID, чиє значення використовується в якості введення для операції checkResponse. Даний ідентифікатор є єдиним засобом для зіставлення клієнтом початкового запиту з відповіддю. Існують також і інші способи для цієї реалізації, про які буде розказано пізніше.
В лістингу 2 представлений типовий обмін повідомленнями для даного сервісу.
Лістинг 2. Обмін повідомленнями AsyncService
<I> Initial Request </ i> <SOAP-ENV: Envelope xmlns: SOAP-ENV = "http://schemas.xmlsoap.org/soap/envelope/" xmlns: SOAP-ENC = "http: // schemas. xmlsoap.org/soap/encoding/ "xmlns: xsi =" http://www.w3.org/2001/XMLSchema-instance "xmlns: xsd =" http://www.w3.org/2001/XMLSchema "> <SOAP-ENV: Body> <m: submitRequest xmlns: m = "http://one.wspattern.developerworks.ibm.com"> <request> <a> String </a> <b> String </ b> <c> String </ c> </ request> </ m: submitRequest> </ SOAP-ENV: Body> </ SOAP-ENV: Envelope> <i> submitRequest Response Відповідь submitRequest </ i> <soapenv: Envelope xmlns : soapenv = "http://schemas.xmlsoap.org/soap/envelope/" xmlns: soapenc = "http://schemas.xmlsoap.org/soap/encoding/" xmlns: xsd = "http: // www. w3.org/2001/XMLSchema "xmlns: xsi =" http://www.w3.org/2001/XMLSchema-instance "> <soapenv: Header /> <soapenv: Body> <p155: submitRequestResponse xmlns: p155 =" http://one.wspattern.developerworks.ibm.com "> <submitRequestReturn> <type> 0 </ type> <correlationID> 1097517621904 </ correlationID> <refresh> 10000 </ refresh> <a xsi: nil =" true "/> <B xsi: nil =" true "/> <c xsi: nil =" true "/> </ submitRequestReturn> </ p155: submitRequestResponse> </ soapenv: Body> </ soapenv: Envelope> <i> Initial checkResponse attempt, no response available, submitted after 10000 miliseconds Первинна спроба checkResponse, відповідь не надійшла, виконується після затримки в 10000 мс </ i> <soapenv: Envelope xmlns: soapenv = "http://schemas.xmlsoap.org/soap / envelope / "xmlns: soapenc =" http://schemas.xmlsoap.org/soap/encoding/ "xmlns: xsd =" http://www.w3.org/2001/XMLSchema "xmlns: xsi =" http: //www.w3.org/2001/XMLSchema-instance "> <soapenv: Header /> <soapenv: Body> <p155: checkResponseResponse xmlns: p155 =" http://one.wspattern.developerworks.ibm.com "> <checkResponseReturn> <type> 0 </ type> <correlationID> 1097517621904 </ correlationID> <refresh> 10000 </ refresh> <a xsi:nil="true"/> <b xsi: nil = "true" /> < c xsi: nil = "true" /> </ checkResponseReturn> </ p155: checkResponseResponse> </ soapenv: Body> </ soapenv: Envelope> <i> Second check Response attempt, submitted after 10000 miliseconds Друга спроба checkResponse, виконується після затримки в 10000 мс </ i> <soapenv: Envelope xmlns: soapenv = "http://schemas.xmlsoap.org/soap/envelope/" xmlns: soapenc = " http://schemas.xmlsoap.org/soap/encoding/ "xmlns: xsd =" http://www.w3.org/2001/XMLSchema "xmlns: xsi =" http://www.w3.org/2001 / XMLSchema-instance "> <soapenv: Header /> <soapenv: Body> <p155: checkResponseResponse xmlns: p155 =" http://one.wspattern.developerworks.ibm.com "> <checkResponseReturn> <type> 1 </ type> <correlationID xsi: nil = "true" /> <refresh> 0 </ refresh> <a> STRING </a> <b> STRING </ b> <c> STRING </ c> </ checkResponseReturn> < / p155: checkResponseResponse> </ soapenv: Body> </ soapenv: Envelope>Реалізація сервісу
Реалізацією сервісу асинхронного шаблону запиту є застосування Java Messaging Service. Для ілюстрації прикладу тут використовується OpenJMS - реалізація постачальника JMS з відкритим вихідним кодом (див. Ресурси по темі ) І IBM® WebSphere® Application Server V5 (сервер додатків). У прикладі використовується конфігурація OpenJMS, визначена за замовчуванням, а також реалізація Web-сервісу J2EE, сумісного з JSR-109. Код для даного прикладу написаний з використанням WebSphere Studio Application Developer (Application Developer) V5.1, який можна завантажити за посиланням з сайту developerWorks (див. Ресурси по темі ). Тут також додається EAR-файл (див. Ресурси по темі ) На той випадок, якщо у вас немає доступу до Application Developer.
На стороні сервера необхідно реалізувати два компонента - обробник запитів і реалізація Web-сервісу. Завданням обробника запитів є зняття запитів з черги і виконання 10-секундної затримки процесу по перетворенню нижнього регістру символів в верхній. Завданням реалізації сервісу є отримання запитів від клієнтів Web-сервісу і постановка їх в чергу для обробки і для доставки відповідей клієнтам, слідуючи операції checkResponse.
У типовому додатку J2EE, згідно специфікації JMS, обробник запитів повинен бути реалізований як Message Driven Bean (компонент, керований повідомленнями). В даному прикладі використовується простий HTTP-сервлет, який реалізує JMS-інтерфейс MessageListener. Сервлет налаштований на ініціалізацію при завантаженні сервера, що дозволяє слухачеві бути доступним для всіх можливих вхідних запитів. Після постановки запиту в чергу той доставляється сервлету-слухачеві.
Лістинг 3. JNDIListenerServlet.java
package com.ibm.developerworks.wspattern.one.helper; import java.util.Enumeration; import java.util.Hashtable; import javax.jms.JMSException; import javax.jms.MapMessage; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.Queue; import javax.jms.QueueConnection; import javax.jms.QueueReceiver; import javax.jms.QueueSender; import javax.jms.QueueSession; import javax.naming.Context; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; public class JNDIListenerServlet extends HttpServlet implements Servlet, MessageListener {private Context context; private QueueConnection connection; private QueueSession session; private Queue queue; private QueueReceiver receiver; public void init () throws ServletException {super.init (); try {context = JNDIHelper.getInitialContext (); connection = JNDIHelper.getConnection (context); session = JNDIHelper.getSession (connection); queue = JNDIHelper.getQueue (context); receiver = JNDIHelper.getQueueReceiver (session, queue); receiver.setMessageListener (this); System.out.println ( "Listener servlet is Listening"); } Catch (Exception e) {}} public void destroy () {try {connection.close (); } Catch (Exception e) {}} public void onMessage (Message message) {try {System.out.println ( "Processing message" + message.getJMSCorrelationID ()); Thread.sleep (10 * 1000); // sleep for ten seconds Queue responseQueue = JNDIHelper.getResponseQueue (context); QueueSender sender = JNDIHelper.getQueueSender (session, responseQueue); MapMessage request = (MapMessage) message; MapMessage response = session.createMapMessage (); response.setJMSCorrelationID (request.getJMSCorrelationID ()); for (Enumeration e = request.getMapNames (); e.hasMoreElements ();) {String name = (String) e.nextElement (); try {response.setString (name, request.getString (name) .toUpperCase ()); } Catch (Exception ex) {}} sender.send (response); } Catch (Exception e) {System.out.println ( "=================="); try {System.out.println ( "THERE WAS AN ERROR PROCESSING THE MESSAGE!" + message.getJMSCorrelationID ()); } Catch (Exception ex) {} e.printStackTrace (System.out); System.out.println ( "=================="); }}}Сервлет JNDIListenerServlet і реалізація сервісу використовують один простий допоміжний клас, створений для цього додатка, який приховує деталі ініціалізації JMS-з'єднання і сесії.
Лістинг 4. JNDIHelper.java
package com.ibm.developerworks.wspattern.one.helper; import java.util.Hashtable; import javax.jms.JMSException; import javax.jms.Queue; import javax.jms.QueueConnection; import javax.jms.QueueConnectionFactory; import javax.jms.QueueReceiver; import javax.jms.QueueSender; import javax.jms.QueueSession; import javax.jms.Session; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; public class JNDIHelper {private static Context context; public static Context getInitialContext () throws NamingException {if (context == null) {Hashtable properties = new Hashtable (); properties.put (Context.INITIAL_CONTEXT_FACTORY, "org.exolab.jms.jndi.InitialContextFactory"); properties.put (Context.PROVIDER_URL, "rmi: // localhost: 1099"); context = new InitialContext (properties); } Return context; } Public static QueueConnection getConnection (Context context) throws NamingException, JMSException {QueueConnectionFactory factory = (QueueConnectionFactory) context.lookup ( "JmsQueueConnectionFactory"); QueueConnection connection = factory.createQueueConnection (); connection.start (); return connection; } Public static QueueSession getSession (QueueConnection connection) throws JMSException {QueueSession session = connection.createQueueSession (false, Session.AUTO_ACKNOWLEDGE); return session; } Public static Queue getQueue (Context context) throws NamingException {Queue queue = (Queue) context.lookup ( "queue1"); return queue; } Public static Queue getResponseQueue (Context context) throws NamingException {Queue queue = (Queue) context.lookup ( "queue2"); return queue; } Public static QueueSender getQueueSender (QueueSession session, Queue queue) throws JMSException {QueueSender sender = session.createSender (queue); return sender; } Public static QueueReceiver getQueueReceiver (QueueSession session, Queue queue) throws JMSException {QueueReceiver receiver = session.createReceiver (queue); return receiver; } Public static QueueReceiver getQueueReceiver (QueueSession session, Queue queue, String selector) throws JMSException {QueueReceiver receiver = session.createReceiver (queue, selector); return receiver; }}Після створення сервлету відредагуйте файл Web-додатки web.xml таким чином, щоб сервлет ініціалізувати при завантаженні сервера. При ініціалізації сервлет створює JMS-з'єднання і реєструє себе в якості слухача в черзі повідомлень OpenJMS, заданої за замовчуванням.
Другим кроком є створення реалізації сервісу. Тут може стати в нагоді робота з Application Developer, який може допомогти в генеруванні різних артефактів для отримання працюючого JSR-109 Web-сервісу. Тепер сфокусуємось виключно на класі реалізації сервісу. Для ілюстрації інших різних файлів конфігурацій Java і XML до даного документу додається вихідний код, який може бути завантажений за посиланням в кінці документа.
Лістинг 5. AsyncService.java
package com.ibm.developerworks.wspattern.one; import javax.jms.MapMessage; import javax.jms.Message; import javax.jms.Queue; import javax.jms.QueueConnection; import javax.jms.QueueReceiver; import javax.jms.QueueSender; import javax.jms.QueueSession; import javax.naming.Context; import com.ibm.developerworks.wspattern.one.helper.JNDIHelper; public class AsyncService {public Response submitRequest (Request request) {Response response = null; try {Context context = JNDIHelper.getInitialContext (); QueueConnection connection = JNDIHelper.getConnection (context); QueueSession session = JNDIHelper.getSession (connection); Queue queue = JNDIHelper.getQueue (context); QueueSender sender = JNDIHelper.getQueueSender (session, queue); MapMessage message = session.createMapMessage (); String corrID = Long.toString (System.currentTimeMillis ()); message.setJMSCorrelationID (corrID); message.setString ( "one", request.getA ()); message.setString ( "two", request.getB ()); message.setString ( "three", request.getC ()); sender.send (message); response = new Response (); response.setType (Response.TYPE_REFRESH); response.setCorrelationID (corrID); response.setRefresh (10 * 1000); return response; } Catch (Exception e) {response = new Response (); response.setType (Response.TYPE_RESPONSE); response.setA (e.getMessage ()); } Return response; } Public Response checkResponse (ResponseCheck check) {String corrID = check.getCorrelationID (); Response response = null; try {Context context = JNDIHelper.getInitialContext (); QueueConnection connection = JNDIHelper.getConnection (context); QueueSession session = JNDIHelper.getSession (connection); Queue queue = JNDIHelper.getResponseQueue (context); String selector = "JMSCorrelationID = '" + corrID + "'"; QueueReceiver receiver = JNDIHelper.getQueueReceiver (session, queue, selector); Message message = receiver.receiveNoWait (); if (message == null) {response = new Response (); response.setType (Response.TYPE_REFRESH); response.setRefresh (10 * 1000); response.setCorrelationID (corrID); } Else {MapMessage resp = (MapMessage) message; response = new Response (); response.setType (Response.TYPE_RESPONSE); response.setA (resp.getString ( "one")); response.setB (resp.getString ( "two")); response.setC (resp.getString ( "three")); }} Catch (Exception e) {} return response; }}У цьому лістингу немає нічого незвичайного. Метод submitRequest готує JMS MapMessage на базі вхідних параметрів. Це повідомлення складається з трьох строкових значень. Після цього повідомлення відправляється в чергу і готується Refresh Response містить ID кореляції, після чого той повертається клієнтові.
Операція checkResponse приймає ID кореляції з вхідних параметрів і встановлює з'єднання з чергою відповіді, запитуючи доставку будь-яких повідомлень з відповідним ID кореляції. Якщо таких повідомлень не існує, операція не чекає їх, а готує інший Refresh Response з новим періодом інтервалу оновлення і повертає його назад запитуючої сторони. Якщо повідомлення доставлено, операція готує і повертає відповідний Request Response.
Для запуску Web-сервісу асинхронного шаблону запиту необхідно розмістити Web-сервіс і запустити сервери OpenJMS і WebSphere.
висновки
Основною перевагою шаблону асинхронних запитів є можливість кореляції запитів і відповідей клієнтом Web-сервісів і постачальником сервісу. У представленому тут прикладі було розглянуто простий ID кореляції одноразового використання та механізм поновлення таймера, властивого цьому окремому наприклад додатки. Для цієї ж мети можна використовувати, наприклад, кілька комбінацій WS- * специфікацій. WS-Addressing Endpoint Reference або WS-Transaction Coordination Context також можуть містити ID кореляції і оновлювати значення таймера. Використання даного шаблону індивідуально для окремих додатків, і незалежно від того, чи використовуєте ви стандартні елементи заголовка SOAP і різні WS- * специфікації, поведінка кожної реалізації операції повинно бути чітко визначено та задокументовано.
У реалізованому тут прікладі для відправкі Запитів и Отримання Відповідей вікорістовується традіційній шаблон обміну повідомленнями SOAP типу запит-відповідь. В якості альтернативи можна використовуват шаблон в стилі REST, в Якій Предложения відправляються сервлету методом HTTP POST, а ВІДПОВІДІ вітягуються з Використання методу HTTP GET. КОЖЕН з ціх підходів є в рівній мірі допустимим и володіє Власний перевага и недолікамі. Вибір підходу здійснюється в залежності від вимоги вашого! Застосування. Наприклад, якщо операція checkResponse вимагатиме використання аутентифікації WS-Security, то в використання моделі взаємодії в стилі REST немає сенсу.
У висновку, можна легко уявити розширення області застосування даного прикладу для виконання запитувачами сторонами детальних запитів статусу в тривалих операціях або навіть для скасування вже виконуваних операцій. Ілюстрація таких можливостей не є завданням даної статті, вам пропонується досліджувати їх самостійно.
Ресурси для скачування
Схожі тими
- Оригінальна стаття "Learn simple, practical Web services design patterns, Part 1"
- Інші документи з серії "Практичне навчання використанню шаблонів Web-сервісів":
- Стаття, що розповідає про шаблон асинхронних запитів "Asynchronous Queries in J2EE" , Де представлені теоретичні основи, необхідні для обговорення шаблонів асинхронних запитів. Опублікувати на сайті Java Ranch , Автор Kyle Brown.
- Посилання на завантаження програми WebSphere Studio Application Developer , Використовуваної для написання даного прикладу програми.
- Посилання на інформацію про програму з відкритим вихідним кодом OpenJMS provider .
- Книжковий магазин Developer Bookstore , Що містить сотні книг про Web-сервісах .
- Безліч інформативних статей і посібників з розробки додатків Web-сервісів в розділі SOA і Web-сервіси на developerWorks Росія.
- ПОСИЛАННЯ по темі:
Вивчення шаблонів проектування Web-сервісів, Частина 2
Вивчення шаблонів проектування Web-сервісів, Частина 3
Прості і корисні моделі проектування Web-служб, частина 4
Підпішіть мене на ПОВІДОМЛЕННЯ до коментарів
Com/developerworks/ru/library/?Quot; encoding = "UTF-8"?