rabbitmq-rpc

rabbitmq-rpc

前面讲的几个交换器,我们都是单向的消息发送,生产者将消息发送给消费者就不管了。在实际业务中,我们有时候要等耐消费者将结果返回给我们,或者说我么需要消费者上的一个功能,一个方法,一个接口返回给我们的值。但是往往我们的系统是不同的子系统,分布在不同的电脑,不能直接通过方法来调用,所以需要使用到RPC(Remote Procedure Call)远程过程调用模式。

RabbitMQ实现RPC的方式很简单,生产者发送一条带有标签(消息ID(correlation_id)+回调队列名称)的消息到发送队列,消费者(也称RPC服务端)从发送队列获取消息并处理业务,解析标签的信息将业务结果发送到指定的回调队列,生产者从回调队列中根据标签的信息获取发送消息的返回结果。

sample:

生产者

package com.enjoy.rabbitmqtest;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.TimeoutException;

public class RpcProducer {
    public  static final String EXCHANGE = "exchange_rpc";
    public  static  final String URL = "localhost";
    public  static  final String USER = "test";
    public  static  final String PASS_WORD = "test";
    public  static  final String VIRTUL = "/test";
    public  static final String ROUTING_KEY ="routekey.rpc";
    public  static final String QUEUE = "queue_rpc";

    public static void main(String[] args) {
        //连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(URL);
        factory.setUsername(USER);
        factory.setPassword(PASS_WORD);
        factory.setVirtualHost(VIRTUL);
        //获取连接
        try {
            Connection conn = factory.newConnection();
            //获取信道
            Channel channel = conn.createChannel();
            //创建交换器
            channel.exchangeDeclare(EXCHANGE,BuiltinExchangeType.DIRECT.getType());

            //声明队列
            channel.queueDeclare(QUEUE, false, false, false, null);

            //将信道和交换器、路由键绑定
            channel.queueBind(QUEUE, EXCHANGE, ROUTING_KEY);

            //此处注意:我们声明了要回复的队列。队列名称由RabbitMQ自动创建。
            //这样做的好处是:每个客户端有属于自己的唯一回复队列,生命周期同客户端
            String replyQueue = channel.queueDeclare().getQueue();

            //发送消息到交换器
            for(int i=0;i<3;i++) {
                //消息相关属性
                String correlationId = UUID.randomUUID().toString();
                String message = "hello rpc-"+i;
                //属性
                AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
                        .replyTo(replyQueue)//回复队列
                        .correlationId(correlationId)//回复correlationId
                        .build();
                System.out.println("Producer发送消息[correlationId="+correlationId
                        + ",mesage="+message+"]");
                channel.basicPublish(EXCHANGE, ROUTING_KEY, false, props, message.getBytes());
                Thread.sleep(1000);
            }

            //声明消费者
            DefaultConsumer consumer = new DefaultConsumer(channel){
                public void handleDelivery(String consumerTag,
                               Envelope envelope,
                               AMQP.BasicProperties properties,
                               byte[] body){
                       System.out.println(System.currentTimeMillis()+",Producer收到回执消息[correlationId="+properties.getCorrelationId()
                               + "mesage="+new String(body)+"]");
                }
            };

            //消费队列消息
            channel.basicConsume(replyQueue,true,consumer);

//            channel.close();
////            conn.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

消费者

package com.enjoy.rabbitmqtest;

import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class RpcConsumer {
    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(RpcProducer.URL);
        factory.setUsername(RpcProducer.USER);
        factory.setPassword(RpcProducer.PASS_WORD);
        factory.setVirtualHost(RpcProducer.VIRTUL);
        Connection conn = factory.newConnection();
        //获取信道
        final  Channel channel = conn.createChannel();

        /*绑定,将队列和交换器通过路由键进行绑定*/
        channel.queueBind(RpcProducer.QUEUE, RpcProducer.EXCHANGE,RpcProducer.ROUTING_KEY);

        System.out.println("waiting for message........");

        //声明消费者
        DefaultConsumer consumer = new DefaultConsumer(channel){
            //这是一个回到函数,服务器端获取到消息,就会调用此方法处理消息
            public void handleDelivery(String consumerTag,
                                       Envelope envelope,
                                       AMQP.BasicProperties properties,
                                       byte[] body) throws IOException {
//                System.out.println("consumerTag="+consumerTag+",envelope="+envelope
//                +",properties="+properties);
                String message = new String(body);
                System.out.println("Consumer收到消息[correlationId="+properties.getCorrelationId()
                        +",message="+message+"]");
                AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder();
                //我们在将要回复的消息属性中,放入从客户端传递过来的correlateId
                builder.correlationId(properties.getCorrelationId());
                AMQP.BasicProperties props = builder.build();
                //发送给回复队列的消息,exchange="",routingKey=回复队列名称
                //因为RabbitMQ对于队列,始终存在一个默认exchange="",routingKey=队列名称的绑定关系
                channel.basicPublish("",properties.getReplyTo(),
                        false,props,("OK-"+properties.getCorrelationId()).getBytes());

            }
        };
        /*消费者正式开始在指定队列上消费消息*/
        channel.basicConsume(RpcProducer.QUEUE,true,consumer);

//        channel.close();
//        conn.close();
    }
}

结果:

生产者:

Producer发送消息[correlationId=cecf5421-0dd5-4bb1-bc4a-de84b2fdd898,mesage=hello rpc-0]
Producer发送消息[correlationId=3819cd8e-16e3-4899-a772-2846a14cef09,mesage=hello rpc-1]
Producer发送消息[correlationId=1502de20-4377-4ba0-b4e8-592c71d82197,mesage=hello rpc-2]
1571543302869,Producer收到回执消息[correlationId=cecf5421-0dd5-4bb1-bc4a-de84b2fdd898mesage=OK-cecf5421-0dd5-4bb1-bc4a-de84b2fdd898]
1571543302869,Producer收到回执消息[correlationId=3819cd8e-16e3-4899-a772-2846a14cef09mesage=OK-3819cd8e-16e3-4899-a772-2846a14cef09]
1571543302869,Producer收到回执消息[correlationId=1502de20-4377-4ba0-b4e8-592c71d82197mesage=OK-1502de20-4377-4ba0-b4e8-592c71d82197]
 

消费者:

waiting for message........
Consumer收到消息[correlationId=cecf5421-0dd5-4bb1-bc4a-de84b2fdd898,message=hello rpc-0]
Consumer收到消息[correlationId=3819cd8e-16e3-4899-a772-2846a14cef09,message=hello rpc-1]
Consumer收到消息[correlationId=1502de20-4377-4ba0-b4e8-592c71d82197,message=hello rpc-2]
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章