java-rabbitmq-官网实例06
描述:
使用两个互通的队列,模拟 RPC 调用
运行:
D6_RPCClient.main();
D6_RPCServer.main();
描述:
使用两个互通的队列,模拟 RPC 调用
运行:
D6_RPCClient.main();
D6_RPCServer.main();
package com.example.tutorials;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.Scanner;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeoutException;
/**
* 使用两个队列,相互接收对方的消息。使用 AMQP.BasicProperties 传输唯一"互联ID",实现RPC请求
* rpc 调用,转换为大写
* @create 2017-08-30
* amqp-client 4.2.0
**/
public class D6_RPCClient {
public static void main(String[] argv) {
D6_RPCClient fibonacciRpc = null;
String response = null;
try {
fibonacciRpc = new D6_RPCClient();
//生成一个,互联ID
final String corrId = UUID.randomUUID().toString();
//发送消息
System.out.println("输入要发送的内容,退出输入 x ");
String message ;
while(true){
Scanner scanner = new Scanner(System.in);
message = scanner.next();
if("x".equals(message))
break;
System.out.println(" [请求] 内容 = "+message);
response = fibonacciRpc.call(message,corrId);
System.out.println(" [响应] 内容 = " + response );
}
}
catch (IOException | TimeoutException | InterruptedException e) {
e.printStackTrace();
}
finally {
if (fibonacciRpc!= null) {
try {
fibonacciRpc.close();
}
catch (IOException _ignore) {}
}
}
}
private Connection connection;
private Channel channel;
/**
* 由 client 发送消息到 "rpc_queue" 队列,server 消费消息,之后 server 将响应写入"应答队列"
*/
private String requestQueueName = "rpc_queue";
/**
* 应答队列
*/
private String replyQueueName;
/**
* 阻塞队列
*/
private final BlockingQueue<String> response = new ArrayBlockingQueue<String>(1);
/**
* rpc 客户端实例
* @throws IOException
* @throws TimeoutException
*/
public D6_RPCClient() throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
//设置登录账号
factory.setHost(ServerInfo.host);
factory.setPort(ServerInfo.port);
factory.setUsername(ServerInfo.uName);
factory.setPassword(ServerInfo.uPwd);
//链接服务器
connection = factory.newConnection();
channel = connection.createChannel();
//声明一个私有排他、自动删除的队列
replyQueueName = channel.queueDeclare().getQueue();
System.out.println(" [x]应答队列名:"+replyQueueName);
}
/**
* 调用
* @param message 消息内容
* @param corrId 关联id
* @return
* @throws IOException
* @throws InterruptedException
*/
public String call(String message,final String corrId) throws IOException, InterruptedException {
//消息的属性,路由报头等等
AMQP.BasicProperties props = new AMQP.BasicProperties
.Builder()
.correlationId(corrId) //互联ID
.replyTo(replyQueueName) //应答队列
.build();
//发布送消息
channel.basicPublish("", requestQueueName, props, message.getBytes("UTF-8"));
//消费者,接收"应答队列"消息
boolean autoAck=true;//自动应答
channel.basicConsume(replyQueueName, autoAck, new DefaultConsumer(channel) {
@Override
public void handleConsumeOk(String consumerTag) {
super.handleConsumeOk(consumerTag);
System.out.println(" [接收应答消息] 已经注册成功! ");
}
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(String.format(
" [响应队列] 请求corrId = %s; 响应corrId = %s; replyTo = %s;"
,corrId
,properties.getCorrelationId()
,properties.getReplyTo()));
if (properties.getCorrelationId().equals(corrId)) {
//将元素e插入到队列末尾,如果插入成功,则返回true;如果插入失败(即队列已满),则返回false;
String str=new String(body, "UTF-8");
boolean wSuccess = response.offer(str);
System.out.println(
" [接收应答消息] 已收到响应,并写入阻塞队列("+wSuccess+",size="+response.size()+");响应内容="+str);
}
}
});
//使用阻塞队列,在 handleDelivery 没有接收到回调消息时一直处于阻塞状态
String result=response.take();
System.out.println(" [接收应答消息] 阻塞队列已经获取到内容! ");
return result;
}
public void close() throws IOException {
connection.close();
}
}
package com.example.tutorials;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 使用两个队列,相互接收对方的消息。使用 AMQP.BasicProperties 传输唯一"互联ID",实现RPC请求
* rpc 调用,转换为大写
* @create 2017-08-30
* amqp-client 4.2.0
**/
public class D6_RPCServer {
/**
* 由 client 发送消息到 "rpc_queue" 队列,server 消费消息,之后 server 将响应写入"应答队列"
*/
private static final String RPC_QUEUE_NAME = "rpc_queue";
public static void main(String[] argv) throws TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
//设置登录账号
factory.setHost(ServerInfo.host);
factory.setPort(ServerInfo.port);
factory.setUsername(ServerInfo.uName);
factory.setPassword(ServerInfo.uPwd);
Connection connection = null;
try {
//链接服务器
connection = factory.newConnection();
final Channel channel = connection.createChannel();
//定义一个队列
boolean duiable=false;//持久化
boolean exclusive = false;//排他队列
boolean autoDelete=false;//没有consumer时,队列是否自动删除
channel.queueDeclare(RPC_QUEUE_NAME, duiable, exclusive, autoDelete, null);
//轮询分发消息
channel.basicQos(1);
System.out.println(" [x] Awaiting RPC requests");
//创建消费者
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleConsumeOk(String consumerTag) {
super.handleConsumeOk(consumerTag);
System.out.println(" [x] 已经注册成功! ");
}
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
final String corrId =properties.getCorrelationId();
//消息的属性,路由报头等等
AMQP.BasicProperties replyProps = new AMQP.BasicProperties
.Builder()
.correlationId(corrId)//互联ID
.build();
System.out.println("=====================");
System.out.println(String.format(" [响应队列] corrId = %s;replyTo = %s;"
,corrId
,replyProps.getReplyTo()));
//响应内容
String response = "";
try {
//接收到的消息
String message = new String(body,"UTF-8");
//int n = Integer.parseInt(message);
System.out.println(" [接收到] 内容 = " + message );
response += getMsg(message);//计算斐波那契数列
System.out.println(" [接收到] 计算结果 = "+response);
}
catch (RuntimeException e){
System.out.println(" [异常] " + e.toString());
}
finally {
//发送消息到应答队列
channel.basicPublish( "" //交换器
, properties.getReplyTo() //路由键
, replyProps //消息属性
, response.getBytes("UTF-8"));
System.out.println(" [响应到] " +
String.format("ReplyTo = %s;消息:%s"
,properties.getReplyTo()
,response));
//手动应答
channel.basicAck(envelope.getDeliveryTag(), false);
System.out.println(" [响应到] " +
String.format("消息ID,basicAck = %s;"
,envelope.getDeliveryTag()));
}
}
};
//启动一个消费者,监听 RPC_QUEUE_NAME 队列
boolean autoAck=false;//自动应答
channel.basicConsume(RPC_QUEUE_NAME, autoAck, consumer);
//loop to prevent reaching finally block
while(true) {
try {
Thread.sleep(100);
} catch (InterruptedException _ignore) {
System.out.println(" [loop] exception," + _ignore.getMessage());
}
}
} catch (IOException | TimeoutException e) {
e.printStackTrace();
}
finally {
if (connection != null)
try {
connection.close();
} catch (IOException _ignore) {}
}
}
/**
* 转换为大写
* @param
* @return
*/
private static String getMsg(String str) {
return String.format("%s => %s",str,str.toUpperCase());
}
}