[list][*][b]RPC,同步消息[/b][/list]
RabbitMQ默认的consumer为异步监听,RPC应用需要实现consumer的同步,可以使用QueueingConsumer(继承与DefaultConsumer,定义了一个堵塞队列LinkedBlockingQueue)实现同步
实际上就是服务端、客户端各定义一个消息队列,相互发送消息,客户端发送消息后同步等待结果返回
[list]
[*][b]注意要点[/b]
[/list]
[i]发送消息时指定回复队列、corrId[/i]:
[i]监听队列,等待服务端反馈(堵塞)[/i]:
[i]服务端接收消息处理后回写处理结果[/i]:
[i]服务端开启手动应答[/i]:
[i]限制服务端最大处理量[/i]:
[list]
[*][b]RPC服务端[/b]
[/list]
[list]
[*][b]RPC客户端[/b]
[/list]
RabbitMQ默认的consumer为异步监听,RPC应用需要实现consumer的同步,可以使用QueueingConsumer(继承与DefaultConsumer,定义了一个堵塞队列LinkedBlockingQueue)实现同步
实际上就是服务端、客户端各定义一个消息队列,相互发送消息,客户端发送消息后同步等待结果返回
[list]
[*][b]注意要点[/b]
[/list]
[i]发送消息时指定回复队列、corrId[/i]:
//发送消息,指定回复消息所在队列
BasicProperties props=new BasicProperties.Builder().correlationId(corrId).replyTo(queueName).build();
channel.basicPublish("", "rpc_queue", props, SerializationUtils.serialize(mes));
[i]监听队列,等待服务端反馈(堵塞)[/i]:
//监听队列,接收服务端回复消息
while(true){
QueueingConsumer.Delivery delivery=consumer.nextDelivery();//堵塞
//do something
break;
}
[i]服务端接收消息处理后回写处理结果[/i]:
channel.basicPublish("", properties.getReplyTo() ,new BasicProperties.Builder().correlationId(properties.getCorrelationId()).build(),
SerializationUtils.serialize("response:"+mes));
[i]服务端开启手动应答[/i]:
//关闭自动应答机制,默认开启;这时候需要手动进行应该
channel.basicConsume("rpc_queue", false, consumer);
channel.basicAck(envelope.getDeliveryTag(), false);
[i]限制服务端最大处理量[/i]:
channel.basicQos(1);
[list]
[*][b]RPC服务端[/b]
[/list]
package com.demo.mq.rabbitmq.example06;
import java.io.IOException;
import java.io.Serializable;
import org.apache.commons.lang3.SerializationUtils;
import com.demo.mq.rabbitmq.MqManager;
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.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
/**
* RPC服务端
* @author sheungxin
*
*/
public class RPCServer{
/**
* RPC服务端,声明一个服务处理队列,接收消息处理后,把结果回写给客户端
* 需要开启手动应答机制,确保服务执行完成
* @param object 消息主体
* @throws IOException
*/
public static void sendAToB(Serializable object) throws Exception{
Connection conn=MqManager.newConnection();
Channel channel=conn.createChannel();
channel.queueDeclare("rpc_queue", false, false, false, null);
channel.basicQos(1);
Consumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body) throws IOException{
String mes=SerializationUtils.deserialize(body);
System.out.println(envelope.getRoutingKey()+":Received :'"+mes+"' done");
//接收到消息后,向发送方回写消息:指定发送方所在队列(properties.getReplyTo())、correlationId
channel.basicPublish("", properties.getReplyTo() ,
new BasicProperties.Builder().correlationId(properties.getCorrelationId()).build(),
SerializationUtils.serialize("response:"+mes));
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
//关闭自动应答机制,默认开启;这时候需要手动进行应该
channel.basicConsume("rpc_queue", false, consumer);
System.out.println("*********8");
}
public static void main(String[] args) throws Exception {
sendAToB("Hello World !");
}
}
[list]
[*][b]RPC客户端[/b]
[/list]
package com.demo.mq.rabbitmq.example06;
import java.util.UUID;
import org.apache.commons.lang3.SerializationUtils;
import com.demo.mq.rabbitmq.MqManager;
import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;
/**
* RPC客户端
* @author sheungxin
*
*/
@SuppressWarnings("deprecation")
public class RPCClient {
/**
* RPC客户端:向服务端处理队列发送消息,发送时指定correlationId、回复队列名称,同时在回复队列上建立consumer,进行监听接收回复消息
* @param mes
* @throws Exception
*/
public static String call(String mes) throws Exception{
String response=null;
Connection conn=MqManager.newConnection();
Channel channel=conn.createChannel();
//创建一个临时队列,用于接收回复消息
String queueName=channel.queueDeclare().getQueue();
QueueingConsumer consumer=new QueueingConsumer(channel);
channel.basicConsume(queueName, true, consumer);
String corrId=UUID.randomUUID().toString();
//发送消息,指定回复消息所在队列
BasicProperties props=new BasicProperties.Builder().correlationId(corrId).replyTo(queueName).build();
channel.basicPublish("", "rpc_queue", props, SerializationUtils.serialize(mes));
//监听队列,接收服务端回复消息
while(true){
QueueingConsumer.Delivery delivery=consumer.nextDelivery();
if(delivery.getProperties().getCorrelationId().equals(corrId)){
response=SerializationUtils.deserialize(delivery.getBody());
break;
}
}
return response;
}
public static void main(String[] args) throws Exception {
System.out.println(call("hello world"));
System.out.println("waiting for rpc is over");
}
}