(转) RabbitMQ学习之远程过程调用(RPC)(java)
http://blog.csdn.net/zhu_tianwei/article/details/40887885
在一般使用RabbitMQ做RPC很容易。客户端发送一个请求消息然后服务器回复一个响应消息。为了收到一个响应,我们需要发送一个'回调'的请求的队列地址。我们可以使用默认队列(在Java客户端除外)。
AMQP协议给消息定义了14个属性。大部分的属性很少使用,除了下面几个:
deliveryMode: 将消息标记为持久(值为2)或瞬态(任何其他值)。你可能记得在第二个教程中使用了这个属性。
contentType:用来设置mime类型。例如经常使用的JSON格式数据,就需要将此属性设置为:application/json。
replyTo: 通常用来命名一个回调队列.
correlationId: 用来关联RPC请求的响应.
RPC工作流程:

1)、客户端启动时,创建了一个匿名的回调队列。
2)、在一个RPC请求中,客户端发送一个消息,它有两个属性:1.REPLYTO,用来设置回调队列名;2.correlationId,对于每个请求都被设置成唯一的值。
3)、请求被发送到rpc_queue队列.
4)、RPC工作者(又名:服务器)等待接收该队列的请求。当收到一个请求,它就会处理并把结果发送给客户端,使用的队列是replyTo字段指定的。
5)、客户端等待接收回调队列中的数据。当接到一个消息,它会检查它的correlationId属性。如果它和设置的相匹配,就会把响应返回给应用程序。
1、RPC服务器的RPCServer.java,接收消息调用rpc并返回结果
- package cn.slimsmart.rabbitmq.demo.rpc;
- import java.security.MessageDigest;
- import com.rabbitmq.client.AMQP;
- import com.rabbitmq.client.AMQP.BasicProperties;
- import com.rabbitmq.client.Channel;
- import com.rabbitmq.client.Connection;
- import com.rabbitmq.client.ConnectionFactory;
- import com.rabbitmq.client.QueueingConsumer;
- //RPC调用服务端
- public class RPCServer {
- private static final String RPC_QUEUE_NAME = "rpc_queue";
- public static void main(String[] args) throws Exception {
- //• 先建立连接、通道,并声明队列
- ConnectionFactory factory = new ConnectionFactory();
- factory.setHost("192.168.36.217");
- factory.setUsername("admin");
- factory.setPassword("admin");
- factory.setPort(AMQP.PROTOCOL.PORT);
- Connection connection = factory.newConnection();
- Channel channel = connection.createChannel();
- channel.queueDeclare(RPC_QUEUE_NAME, false, false, false, null);
- //•可以运行多个服务器进程。通过channel.basicQos设置prefetchCount属性可将负载平均分配到多台服务器上。
- channel.basicQos(1);
- QueueingConsumer consumer = new QueueingConsumer(channel);
- //打开应答机制autoAck=false
- channel.basicConsume(RPC_QUEUE_NAME, false, consumer);
- System.out.println(" [x] Awaiting RPC requests");
- while (true) {
- QueueingConsumer.Delivery delivery = consumer.nextDelivery();
- BasicProperties props = delivery.getProperties();
- BasicProperties replyProps = new BasicProperties.Builder()
- .correlationId(props.getCorrelationId()).build();
- String message = new String(delivery.getBody());
- System.out.println(" [.] getMd5String(" + message + ")");
- String response = getMd5String(message);
- //返回处理结果队列
- channel.basicPublish("", props.getReplyTo(), replyProps,
- response.getBytes());
- //发送应答
- channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
- }
- }
- // 模拟RPC方法 获取MD5字符串
- public static String getMd5String(String str) {
- MessageDigest md5 = null;
- try {
- md5 = MessageDigest.getInstance("MD5");
- } catch (Exception e) {
- System.out.println(e.toString());
- e.printStackTrace();
- return "";
- }
- char[] charArray = str.toCharArray();
- byte[] byteArray = new byte[charArray.length];
- for (int i = 0; i < charArray.length; i++)
- byteArray[i] = (byte) charArray[i];
- byte[] md5Bytes = md5.digest(byteArray);
- StringBuffer hexValue = new StringBuffer();
- for (int i = 0; i < md5Bytes.length; i++) {
- int val = ((int) md5Bytes[i]) & 0xff;
- if (val < 16)
- hexValue.append("0");
- hexValue.append(Integer.toHexString(val));
- }
- return hexValue.toString();
- }
- }
2.客户端RPCClient.java,发送rpc调用消息,接收结果
- package cn.slimsmart.rabbitmq.demo.rpc;
- import com.rabbitmq.client.AMQP;
- import com.rabbitmq.client.Channel;
- import com.rabbitmq.client.Connection;
- import com.rabbitmq.client.ConnectionFactory;
- import com.rabbitmq.client.QueueingConsumer;
- import com.rabbitmq.client.AMQP.BasicProperties;
- //RPC调用客户端
- public class RPCClient {
- private Connection connection;
- private Channel channel;
- private String requestQueueName = "rpc_queue";
- private String replyQueueName;
- private QueueingConsumer consumer;
- public RPCClient() throws Exception {
- //• 先建立一个连接和一个通道,并为回调声明一个唯一的'回调'队列
- ConnectionFactory factory = new ConnectionFactory();
- factory.setHost("192.168.36.217");
- factory.setUsername("admin");
- factory.setPassword("admin");
- factory.setPort(AMQP.PROTOCOL.PORT);
- connection = factory.newConnection();
- channel = connection.createChannel();
- //• 注册'回调'队列,这样就可以收到RPC响应
- replyQueueName = channel.queueDeclare().getQueue();
- consumer = new QueueingConsumer(channel);
- channel.basicConsume(replyQueueName, true, consumer);
- }
- //发送RPC请求
- public String call(String message) throws Exception {
- String response = null;
- String corrId = java.util.UUID.randomUUID().toString();
- //发送请求消息,消息使用了两个属性:replyto和correlationId
- BasicProperties props = new BasicProperties.Builder()
- .correlationId(corrId).replyTo(replyQueueName).build();
- channel.basicPublish("", requestQueueName, props, message.getBytes());
- //等待接收结果
- while (true) {
- QueueingConsumer.Delivery delivery = consumer.nextDelivery();
- //检查它的correlationId是否是我们所要找的那个
- if (delivery.getProperties().getCorrelationId().equals(corrId)) {
- response = new String(delivery.getBody());
- break;
- }
- }
- return response;
- }
- public void close() throws Exception {
- connection.close();
- }
- }
3、运行client主函数RPCMain.java
- package cn.slimsmart.rabbitmq.demo.rpc;
- public class RPCMain {
- public static void main(String[] args) throws Exception {
- RPCClient rpcClient = new RPCClient();
- System.out.println(" [x] Requesting getMd5String(abc)");
- String response = rpcClient.call("abc");
- System.out.println(" [.] Got '" + response + "'");
- rpcClient.close();
- }
- }
先运行服务端,再运行RPCMain,发送消息调用RPC。
这里介绍的是该设计不是实现RPC服务的唯一可能,但它有一些重要的优点:
1)如果RPC服务器速度太慢,你可以通过运行多个RPC服务器。尝试在一个新的控制台上运行第二RPCServer。
2)RPC客户端只发送和接收一个消息。不需要queueDeclare那样要求同步调用。因此,RPC客户端只需要在一个网络上发送和接收为一个单一的RPC请求。
(转) RabbitMQ学习之远程过程调用(RPC)(java)的更多相关文章
- RabbitMQ入门(6)——远程过程调用(RPC)
在RabbitMQ入门(2)--工作队列中,我们学习了如何使用工作队列处理在多个工作者之间分配耗时任务.如果我们需要运行远程主机上的某个方法并等待结果怎么办呢?这种模式就是常说的远程过程调用(Remo ...
- RabbitMQ入门:远程过程调用(RPC)
假如我们想要调用远程的一个方法或函数并等待执行结果,也就是我们通常说的远程过程调用(Remote Procedure Call).怎么办? 今天我们就用RabbitMQ来实现一个简单的RPC系统:客户 ...
- RabbitMQ学习(二):Java使用RabbitMQ要点知识
转 https://blog.csdn.net/leixiaotao_java/article/details/78924863 1.maven依赖 <dependency> <g ...
- (转)RabbitMQ学习之主题topic(java)
http://blog.csdn.net/zhu_tianwei/article/details/40887775 参考:http://blog.csdn.NET/lmj623565791/artic ...
- (转) RabbitMQ学习之发布/订阅(java)
http://blog.csdn.net/zhu_tianwei/article/details/40887733 参考:http://blog.csdn.NET/lmj623565791/artic ...
- RabbitMQ学习第一记:用java连接RabbitMQ
1.什么是RabbitMQ MQ(Message Queue):消息队列,是服务端设计的一个可以存储大量消息的队列,并提供客户端操作队列的方法:生产队列(向队列中添加数据).消费队列(从队列中取数据) ...
- RabbitMQ学习(一):RabbitMQ要点简介
转载:http://blog.csdn.net/leixiaotao_java/article/details/78909760#t0 1.什么是RabbitMQ? RabbitMQ是由Erlang语 ...
- [译]RabbitMQ教程C#版 - 远程过程调用(RPC)
先决条件 本教程假定 RabbitMQ 已经安装,并运行在localhost标准端口(5672).如果你使用不同的主机.端口或证书,则需要调整连接设置. 从哪里获得帮助 如果您在阅读本教程时遇到困难, ...
- java 执行sql错误 传入的表格格式数据流(TDS)远程过程调用(RPC)协议流不正确。参数 1 (""): 数据类型 0x38 未知
连接数据库时设置:Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE ,ResultSet.CONCUR_R ...
随机推荐
- react-native页面间传递数据的几种方式
1. 利用react-native 事件DeviceEventEmitter 监听广播 应用场景: - 表单提交页面, A页面跳转到B页面选人, 然后返回A页面, 需要将B页面选择的数据传回A页面. ...
- elementUI 时间选择器,时间选择快捷键
elementUI的时间快捷键,使用属性:picker-options="pickerOptions",由于pickerOptions的定义很长,也在其他地方共用,因此建议提取出来 ...
- Java设计模式之 — 策略(Strategy)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/8986285 今天你的leader兴致冲冲地找到你,希望你可以帮他一个小忙,他现在急 ...
- jquery怎样获取多个复选框的值?
jquery的遍历方法可以获取复选框所欲的选中值 1 2 $("input:checkbox:checked").each(function(index,element)); ...
- Java Web学习总结(22)——使用kaptcha生成验证码
kaptcha是一个简单好用的验证码生成工具,通过配置,可以自己定义验证码大小.颜色.显示的字符等等.下面就来讲一下如何使用kaptcha生成验证码以及在服务器端取出验证码进行校验. 一.搭建测试环境 ...
- (32)Spring Boot使用@SpringBootApplication注解,从零开始学Spring Boot
[来也匆匆,去也匆匆,在此留下您的脚印吧,转发点赞评论] 如果看了我之前的文章,这个节你就可以忽略了,这个是针对一些刚入门的选手存在的困惑进行写的一篇文章. 很多Spring Boot开发者总是使用 ...
- POJ 2374
挺水的一道线段树+DP题.可以从底往上添加线段,每添加线段之前查询端点所被覆盖的区间线段.再从最顶往下DP,每次从端点出发,递推覆盖该端点的区间线段的两端的值即可. #include <cstd ...
- Python去除多余空格
今天做爬虫时.发现结果中好多多余的空格.然后有强迫症的我当然不会放过 " xyz ".strip() # returns "xyz" " xyz &q ...
- Makefileeasy犯错的语法
1.引言 近期学习android的Build系统,接触最多的自然就是Makefile语法.发现非常多easy出错的地方,不避开这些错误语法没法真正了解Makefile的内涵.以下就介绍遇到的一些让人困 ...
- JS——BOM操作(基本用法与实现:open()、close()、scrollTop等了解)
(1)window.open() 定义和用法 open() 方法用于打开一个新的浏览器窗口或查找一个已命名的窗口 语法 window.open(URL,name,specs,replace) [默认填 ...