2019独角兽企业重金招聘Python工程师标准>>>

JMS是用来为发送者和接收者解耦的;

消息通过一个进程发送给代理,然后代理在另外一个进程异步的接收消息,一种可以利用JMS来实现的系统架构被称为请求/应答。

概括的说:一个请求/应答场景包括一个发送消息(请求)并期望接收消息返回值(应答)的应用程序。通常,这样的系统被设计成CS架构,服务端和客户端通过网络传输协议(TCP,UDP等等)同步的进行通信。这种架构方式在可扩展方面具有明显的限制,很难获得长远发展。消息系统正是为此而生,通过基于消息的请求/应答设计模式能够设计出易于扩展的系统主要以异步处理方式实现。

请求/应答系统:注意,客户端包含消息生产者(producer)和消息消费者(consumer),并且工作者(worker)也包含消息生产者(producer)和消息消费者(consumer)。后面将解释客户端和工作者(worker)。

首先,消息生产者创建一个以JMS消息格式封装的请求并在消息中设置一些重要的属性,包括correlation ID(通过消息的JMSCorrelationID属性设置)和reply destination(响应发送目的地,通过JMSReplyTo属性设置)。correlation ID属性非常重要,因为在请求数量非常多时需要使用这个属性来关联请求和应答。属性指定应答发往的目的地(通常是一个临时的JMS目的地,因为reply destination比较消耗资源)。接下来,客户端配置,一个消息消费者监听响应消息目的地(reply destination)。

其次,一个工作者(woker)接收到请求,并处理请求,然后发送一个响应消息到请求消息的JMSReplyTo属性指定的目的中。响应消息必须用原始请求消息correlation ID的属性值来设置JMSCorrelationID属性,当客户端收到响应消息后,可以通过correlation ID关联到初始的请求。

这种结构如何实现高可扩展性,想象一个场景:单一的工作者无法处理大量并发的请求负载时怎么办?当然没问题:可以添加工作者来平衡负载。这些工作者甚至分布到自不同的主机,这也是这种可扩展性设计中最重要的部分。因为工作者并不是在争夺相同主机上的资源,所以唯一的限制是代理中消息的最大吞吐量,它比使用普通的客户端服务器架构能达到的最大吞吐量要大得多。并且,ActiveMQ可以进行水平和垂直扩展。

下面让我们看看请求/应答程序的基本实现.

实现服务和工作者(worker)

首先,需要关注的是系统中使用的消息代理。先要启动代理,以便两边程序都启动时可以连接到代理。为方便说明本例中使用一个嵌入式代理。其次,需要启动系统中的工作者(worker)。工作者由消息监听器组成,用来接收处理消息和发送消息响应。

在请求/响应实例创建中一个代理,消费者以及生产者

public void start() throws Exception  {createBroker();setupConsumer();
}
private void createBroker() throws Exception  {broker = new BrokerService();broker.setPersistent(false);broker.setUseJmx(false);broker.addConnector(brokerUrl);broker.start();
}
private void setupConsumer() throws JMSException  {ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerUrl);Connection connection;connection = connectionFactory.createConnection();connection.start();session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);Destination adminQueue = session.createQueue(requestQueue);producer = session.createProducer(null);producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);consumer = session.createConsumer(adminQueue);consumer.setMessageListener(this);
}
public void stop() throws Exception  {producer.close();consumer.close();session.close();broker.stop();
}

从代码中可以看到,start()方法调用一个方法创建并启动一个嵌入式代理,另外一个方法用于启动工作者. createBroker()方法使用BrokerService类来创建一个嵌入式代理.setupConsumer()方法通过创建 JMS所需的所有对象来发送和接收消息,这些JMS对象包括:一个连接,一个session,一个消息目的地,一个消息消费者和一个生产者。 创建消息生产者的时候没有设置默认的消息目的地,因为该生产者会将消息发送到每个消息的 JMSReplyTo属性所指定的目的地中。下面再详细看下请求/响应中的监听者,看看它是如何处理每个请求的:

public void onMessage(Message message)  {try{TextMessage response = this.session.createTextMessage();if (message instanceof TextMessage) {TextMessage txtMsg = (TextMessage) message;String messageText = txtMsg.getText();response.setText(handleRequest(messageText));}response.setJMSCorrelationID(message.getJMSCorrelationID());producer.send(message.getJMSReplyTo(), response);}  catch (JMSException e)    {e.printStackTrace();}
}
public String handleRequest(String messageText)  {return "Response to '" + messageText + "'";
}

消息监听器创建一个新消息,并设置合适的correlation ID,然后将消息发送到响应消息队列。很简单但是很重要,尽管在这个消息监听器的实现中没做什么惊天动地的事情,但是它展示了工作者完成器任务的必要的基本步骤。根据需求,可以在监听器中添加其他任意额外的操作或者数据库访问操作。

启动服务很简单:创建一个server实例并调用start()方法。main方法容纳了server的的所有功能,如下面的代码清单所示:

public static void main(String[] args) throws Exception  {Server server = new Server();server.start();System.out.println();System.out.println("Press any key to stop the server");System.out.println();System.in.read();server.stop();
}

一旦server启动完成,worker就正常运行了,这样所有准备接收客户端请求的工作已经就绪。

实现客户端:客户端要做到工作是初始化发送到代理的请求。这是整个请求/应答过程的起点,并且通常在一个业务逻辑处理过程中触发。这个过程可能是接受订单,履行订单,整合各类业务系统,财务状况中的买入卖出等,不管是什么情况,请求/响应过程从发送一个消息开始。发送一个消息到代理需要标准的连接(connection),session,消息目的地(destination)以及消息生产者(producer),它们都是在client的start()方法中创建的。下面的的代码清单中提供了完整的

示例:

启动和停止响应/应答系统客户端的方法

public void start() throws JMSException  {ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerUrl);connection = connectionFactory.createConnection();connection.start();session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);Destination adminQueue = session.createQueue(requestQueue);producer = session.createProducer(adminQueue);producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);tempDest = session.createTemporaryQueue();consumer = session.createConsumer(tempDest);consumer.setMessageListener(this);
}public void stop() throws JMSException  {producer.close();consumer.close();session.close();connection.close();
}

消息生产者发送消息到请求队列中,然后消息消费者监听新创建的临时队列。下面的代码中展示了实现客户端的真正逻辑:

public void request(String request) throws JMSException  {System.out.println("Requesting: " + request);TextMessage txtMessage = session.createTextMessage();txtMessage.setText(request);txtMessage.setJMSReplyTo(tempDest);String correlationId = UUID.randomUUID().toString();txtMessage.setJMSCorrelationID(correlationId);this.producer.send(txtMessage);
}
public void onMessage(Message message)  {try{System.out.println("Received response for: " + ((TextMessage) message).getText());}  catch(JMSException e)    {e.printStackTrace();}
}

所示的request()方法使用请求内容创建一个消息并设置JMSReplyTo属性值,接着发送这个消息到临时队列,最后设置correlation ID 属性值。上述3个步骤很重要.在这个例子中,是使用一个随机的UUID值来设置correlation ID的,也还可以使用其他任何ID生成器来生成这个ID。

接下就可以发送一个请求了,启动客户端也可以像启动sever一样,简单的使用一个main方法即可,下面是代码清单:

启动请求/应答系统客户端

public static void main(String[] args) throws Exception  {Client client = new Client();client.start();int i = 0;while (i++ < 10)  {client.request("REQUEST-" + i);}Thread.sleep(3000); //wait for repliesclient.stop();
}

如前文所述,这个是一个简单的请求/应答系统的实现。因此,启动客户端以后,会发送10个请求到代理。运行这个实例程序需要两个终端:一个用于运行server,另一个用于client,必须先运行server。sever通过Server类来实现,client通过Client类实现。因为这两个类都是通过main方法初始化的,所以运行它们很容易。注意:到当client启动后,送了10个请求用于激活请求/响应进程,然后收到了来自worker的响应。尽管这个例子很简单,但是日后必将是你在其他业务中实现请求/响应系统的参考。

使用请求/应答模式,代理将每秒钟收到的来自无数的客户端的成千上万个请求全部分发到不同的主机中处理。 在生产系统中,会使用更多的代理实例用于备份,失效转移以及负载均衡。这些代理也会被分布于很多的主机上。处理如此多请求的唯一方法是使用多工作者(worker)。因为消息发送者发送消息的速度可能比消息消费者接收并处理消息的速度快的多。所以就需要大量的工作者(worker),这些工作者同样也分布于大量的主机上。

使用多工作者的好处是任何的工作者都可以根据需要进行启用或者停用,而整个系统不会收到影响。消息生产者和工作者会正常处理消息,即使她们当中的一些已经崩溃了,也不会影响系统运行。这正是那些大型系统可以处理海量负载的原因--使用前文介绍过的基于请求/应答模式的异步消息系统.

JMS的API可以说是繁琐的,因为它要求开发者书写大量的初始化代码用于初始化必要的JMS对象,包括connection, session, producer, consumer等等。使用Spring框架通过提供可靠的API来帮助开发者移除(类似于JMS对象初始化)的那些固定的代码,以便简化整个配置过程。这正式使用Spring框架带来的好处。

转载于:https://my.oschina.net/mclimber/blog/1510875

使用JMS实现请求/应答程序相关推荐

  1. icmp时间戳请求和应答程序实现_ICMP报文详解之ping实现

    ping是向网络主机发送ICMP回显请求(ECHO_REQUEST)分组,是TCP/IP协议的一部分.主要可以检查网络是否通畅或者网络连接速度快慢,从而判断网络是否正常. ping命令底层使用的是IC ...

  2. zmq 可靠的请求-应答模式

    <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_ht ...

  3. ZMQ 第四章 可靠的请求-应答模式

    感谢原创作者的分享! # ZMQ 第四章 可靠的请求-应答模式 第三章中我们使用实例介绍了高级请求-应答模式,本章我们会讲述请求-应答模式的可靠性问题,并使用ZMQ提供的套接字类型组建起可靠的请求-应 ...

  4. ZeroMQ 中文指南 第四章 可靠的请求-应答模式【转载】

    此文章转载自GitHub : https://github.com/anjuke/zguide-cn 作者信息如下. ZMQ 指南 作者: Pieter Hintjens ph@imatix.com, ...

  5. ZeroMQ指南:第4章:可靠的请求-应答

    本文是阅读http://zguide2.zeromq.org/page:all#toc65的笔记. 第三章用实际的示例探讨了请求-回应模式的高级用法.本章将探讨可靠性的问题,在ZeroMQ的核心请求- ...

  6. 初探ZeroMQ(二) 请求-应答模式中套结字总结

    参考资料:ØMQ - The Guide(英文) 参考资料:ØMQ - The Guide(中文) 本文主要介绍和总结在请求-应答模式中各种套结字的行为. 套结字简介 来点通俗易懂的,先认识下请求-应 ...

  7. Netty教程系列(一)——netty入门应答程序

    Netty简介 Netty是一个异步通信.事件驱动基于NIO编写的高性能高并发的java网络编程框架.下面通过一个简单的服务器应答程序来完成Netty的初步学习. 代码地址:https://gitee ...

  8. ZeroMQ学习笔记(4)——可靠的请求-应答模式

    第四章 可靠的请求-应答模式 懒惰海盗模式:来自客户端的可靠的请求-应答. 简单海盗模式:使用负载均衡的可靠的请求-应答. 偏执海盗模式:使用信号检测的可靠的请求-应答. 管家模式:面向服务的可靠排队 ...

  9. 【转】WCF请求应答(Request-Reply)、单向操作(One-Way)、回调操作(Call Back)

    [1]请求应答(Request-Reply): 请求应答模式是默认的操作模式.这与经典的C/S编程类似,客户端发送请求,阻塞客户端进程,服务端返回操作结果.请求应答模式与绑定对应关系 : 绑定协议名称 ...

最新文章

  1. Educational Codeforces Round 105 (Rated for Div. 2) C. 1D Sokoban
  2. Nginx的proxy_cache缓存功能
  3. 无密码身份验证:安全、简单且部署快速
  4. Linux环境下手动配置sbt
  5. Android:在安卓中使用TFLite模型
  6. C#获取本机IP地址字符串
  7. constraint mysql_MySQL(Constraint)
  8. C++ Socket通信类的封装(还有点小bug)
  9. python选择语句是什么语句_Python语言中的三种选择语句
  10. VS 2017 + EF6 + MySQL5.7 建立实体模型闪退问题
  11. 北大核刊最新版2020目录_重磅!最新版CSSCI 来源期刊目录(2019-2020)
  12. 怎么用便签在手机上记事?
  13. Java使用Imageio拆分gif图片时保存的图片变为黑色
  14. Vue 实现翻页器 下一页 处理显示多页面要下一页非表格
  15. Java练习——输入n个数,存入数组,进行排序输出
  16. Java 多线程面试题及回答
  17. 2021年大学生求职热门行业公布,如何拿下高薪工作?
  18. 区块链+物联网“网链”CP带你打开新世界
  19. Linux解压命令汇总
  20. python武林世界

热门文章

  1. java字符串编程_java字符串抉择
  2. Java 比较相等 == or .equal()?
  3. HTTP文件浏览(静态文件+express4.x+md/code文件渲染)
  4. 写给初学前端工程师的一封信 (转于Kejun)
  5. Android studio 查看sha1
  6. 【备份恢复】Oracle 数据备份与恢复微实践
  7. 【semantic】本体和语义网的研究方向
  8. IHttpHandler的妙用之防盗链
  9. (原创)无废话C#设计模式之十二:Bridge
  10. NCBI SRA数据库使用详解