(八) RabbitMQ实战教程(面向Java开发人员)之RabbitMQ实现异步RPC

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/RobertoHuang/article/details/79616581

RabbitMQ实现异步RPC

本系列博客源码GIT地址:https://github.com/RobertoHuang/RGP-RABBITMQ.git

RabbitMQ Java Client

服务端步骤:

1.服务端监听一个队列,监听客户端发送过来的消息
2.收到消息之后调用RPC服务得到调用结果
3.从消息属性中获取reply_to,correlation_id属性,把调用结果发送给reply_to指定的队列,发送的消息属性要带上correlation_id

客户端步骤:

1.监听reply_to队列
2.发送消息,消息属性需要带上reply_to,correlation_id
3.服务端处理完之后reply_to对应的队列就会收到异步处理结果消息
4.收到消息之后进行处理,根据消息的correlation_id找到对应的请求

1.创建连接工具类

public class ChannelUtils {
    public static Channel getChannel(String connectionDescription) {
        try {
            ConnectionFactory connectionFactory = getConnectionFactory();
            Connection connection = connectionFactory.newConnection(connectionDescription);
            return connection.createChannel();
        } catch (Exception e) {
            throw new RuntimeException("获取Channel连接失败");
        }
    }

    private static ConnectionFactory getConnectionFactory() {
        ConnectionFactory connectionFactory = new ConnectionFactory();

        connectionFactory.setHost("192.168.56.128");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");
        connectionFactory.setUsername("roberto");
        connectionFactory.setPassword("roberto");

        connectionFactory.setAutomaticRecoveryEnabled(true);
        connectionFactory.setNetworkRecoveryInterval(10000);

        Map<String, Object> connectionFactoryPropertiesMap = new HashMap();
        connectionFactoryPropertiesMap.put("principal", "RobertoHuang");
        connectionFactoryPropertiesMap.put("description", "RGP订单系统V2.0");
        connectionFactoryPropertiesMap.put("emailAddress", "[email protected]");
        connectionFactory.setClientProperties(connectionFactoryPropertiesMap);

        return connectionFactory;
    }
}

2.创建模拟RPC调用方法

public class RPCMethod {
    public static String addOrder(String orderInfo) {
        try {
            System.out.println("orderInfo已添加到数据库");
            return "订单ID";
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }
}

3.创建RPC服务端

public class RPCServer {
    public static void main(String[] args) throws IOException {
        Channel channel = ChannelUtils.getChannel("RGP订单系统Server端");

        channel.queueDeclare("roberto.order.add", true, false, false, new HashMap<>());
        channel.exchangeDeclare("roberto.order", BuiltinExchangeType.DIRECT, true, false, false, new HashMap<>());

        channel.basicConsume("roberto.order.add", true, "RGP订单系统Server端", new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String replyTo = properties.getReplyTo();
                String correlationId = properties.getCorrelationId();

                System.out.println("----------收到RPC调用请求消息----------");
                System.out.println(consumerTag);
                System.out.println("消息属性为:" + properties);
                System.out.println("消息内容为" + new String(body));
                try {
                    String orderId = RPCMethod.addOrder(new String(body));
                    AMQP.BasicProperties replyProperties = new AMQP.BasicProperties().builder().deliveryMode(2).contentType("UTF-8").correlationId(correlationId).build();
                    channel.basicPublish("", replyTo, replyProperties, orderId.getBytes());
                    System.out.println("----------RPC调用成功 结果已返回----------");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

4.创建RPC客户端

public class RPCClient {
    public static void main(String[] args) throws IOException, TimeoutException {
        Channel channel = ChannelUtils.getChannel("RGP订单系统Client端");

        channel.queueDeclare("roberto.order.add", true, false, false, new HashMap<>());
        channel.exchangeDeclare("roberto.order", BuiltinExchangeType.DIRECT, true, false, new HashMap<>());
        channel.queueBind("roberto.order.add", "roberto.order", "add", new HashMap<>());

        String replyTo = "roberto.order.add.replay";
        channel.queueDeclare(replyTo, true, false, false, new HashMap<>());
        String correlationId = UUID.randomUUID().toString();
        AMQP.BasicProperties basicProperties = new AMQP.BasicProperties().builder().deliveryMode(2).contentType("UTF-8").correlationId(correlationId).replyTo(replyTo).build();
        channel.basicPublish("roberto.order", "add", true, basicProperties, "订单消息信息".getBytes());
        channel.basicConsume("roberto.order.add.replay", true, "RGP订单系统Client端", new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("----------RPC调用结果----------");
                System.out.println(consumerTag);
                System.out.println("消息属性为:" + properties);
                System.out.println("消息内容为" + new String(body));
            }
        });
    }
}

5.依次启动服务端和客户端,控制台输出如下

----------收到RPC调用请求消息----------
RGP订单系统Server端
消息属性为:#contentHeader<basic>(content-type=UTF-8, content-encoding=null, headers=null, delivery-mode=2, priority=null, correlation-id=585555ce-f5d5-4a98-bdf0-62f16965e2c8, reply-to=roberto.order.add.replay, expiration=null, message-id=null, timestamp=null, type=null, user-id=null, app-id=null, cluster-id=null)
消息内容为订单消息信息
orderInfo已添加到数据库
----------RPC调用成功 结果已返回----------


----------RPC调用结果----------
RGP订单系统Client端
消息属性为:#contentHeader<basic>(content-type=UTF-8, content-encoding=null, headers=null, delivery-mode=2, priority=null, correlation-id=585555ce-f5d5-4a98-bdf0-62f16965e2c8, reply-to=null, expiration=null, message-id=null, timestamp=null, type=null, user-id=null, app-id=null, cluster-id=null)
消息内容为订单ID

Spring AMQP配置方式

使用Spring AMQP进行异步RPC十分简单,我们只需要在客户端发送消息请求的时候使用sendAndReceive()就会同步等待服务端返回结果信息(返回结果消息未服务端消费消息处理结果返回值),如果超时服务端未响应信息,则返回结果信息为NULL,可以通过rabbitTemplate.setReplyTimeout(10000)设置超时时间

1.创建模拟RPC调用方法

public class RPCMethod {
    public static String addOrder(byte[] orderInfo) {
        try {
            System.out.println(new String(orderInfo, "UTF-8"));
            System.out.println("orderInfo已添加到数据库");
            return "订单ID";
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }
}

2.创建SpringAMQP Server端配置类

扫描二维码关注公众号,回复: 3810983 查看本文章
@Configuration
public class SpringAMQPServerConfig {
    @Bean
    public CachingConnectionFactory connectionFactory() {
        ConnectionFactory connectionFactory = new ConnectionFactory();

        connectionFactory.setHost("192.168.56.128");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");
        connectionFactory.setUsername("roberto");
        connectionFactory.setPassword("roberto");

        connectionFactory.setAutomaticRecoveryEnabled(true);
        connectionFactory.setNetworkRecoveryInterval(10000);

        Map<String, Object> connectionFactoryPropertiesMap = new HashMap();
        connectionFactoryPropertiesMap.put("principal", "RobertoHuang");
        connectionFactoryPropertiesMap.put("description", "RGP订单系统V2.0");
        connectionFactoryPropertiesMap.put("emailAddress", "[email protected]");
        connectionFactory.setClientProperties(connectionFactoryPropertiesMap);
        CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(connectionFactory);

        return cachingConnectionFactory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(CachingConnectionFactory cachingConnectionFactory) {
        return new RabbitAdmin(cachingConnectionFactory);
    }

    @Bean
    public Exchange exchange() {
        return new DirectExchange("roberto.order", true, false, new HashMap<>());
    }

    @Bean
    public Queue queue() {
        Queue queue = new Queue("roberto.order.add", true, false, false, new HashMap<>());
        return queue;
    }

    @Bean
    public Binding binding() {
        Binding binding = new Binding("roberto.order.add", Binding.DestinationType.QUEUE, "roberto.order", "add", new HashMap<>());
        return binding;
    }

    @Bean
    public MessageListenerContainer messageListenerContainer(CachingConnectionFactory cachingConnectionFactory) {
        SimpleMessageListenerContainer messageListenerContainer = new SimpleMessageListenerContainer();
        messageListenerContainer.setConnectionFactory(cachingConnectionFactory);
        messageListenerContainer.setQueueNames("roberto.order.add");

        messageListenerContainer.setConcurrentConsumers(5);
        messageListenerContainer.setMaxConcurrentConsumers(10);

        Map<String, Object> argumentMap = new HashMap();
        messageListenerContainer.setConsumerArguments(argumentMap);
        messageListenerContainer.setConsumerTagStrategy(new ConsumerTagStrategy() {
            @Override
            public String createConsumerTag(String s) {
                return "RGP订单系统ADD处理逻辑消费者";
            }
        });

        RPCMethod rpcMethod = new RPCMethod();
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(rpcMethod);
        messageListenerAdapter.setDefaultListenerMethod("addOrder");

        messageListenerContainer.setMessageListener(messageListenerAdapter);
        return messageListenerContainer;
    }
}

3.创建Server端启动类

@ComponentScan("roberto.growth.process.rabbitmq.rpc.spring.amqp.server")
public class ServerApplication {
    public static void main(String[] args) {
        new AnnotationConfigApplicationContext(ServerApplication.class);
    }
}

4.创建客户端配置类

@Configuration
public class SpringAMQPClientConfig {
    @Bean
    public CachingConnectionFactory connectionFactory() {
        ConnectionFactory connectionFactory = new ConnectionFactory();

        connectionFactory.setHost("192.168.56.128");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");
        connectionFactory.setUsername("roberto");
        connectionFactory.setPassword("roberto");

        connectionFactory.setAutomaticRecoveryEnabled(true);
        connectionFactory.setNetworkRecoveryInterval(10000);

        Map<String, Object> connectionFactoryPropertiesMap = new HashMap();
        connectionFactoryPropertiesMap.put("principal", "RobertoHuang");
        connectionFactoryPropertiesMap.put("description", "RGP订单系统V2.0");
        connectionFactoryPropertiesMap.put("emailAddress", "[email protected]");
        connectionFactory.setClientProperties(connectionFactoryPropertiesMap);
        CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(connectionFactory);

        return cachingConnectionFactory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(CachingConnectionFactory cachingConnectionFactory) {
        return new RabbitAdmin(cachingConnectionFactory);
    }

    @Bean
    public RabbitTemplate rabbitTemplate(CachingConnectionFactory cachingConnectionFactory) {
        return new RabbitTemplate(cachingConnectionFactory);
    }

    @Bean
    public Exchange exchange() {
        return new DirectExchange("roberto.order", true, false, new HashMap<>());
    }
}

5.创建客户端启动类

@ComponentScan("roberto.growth.process.rabbitmq.rpc.spring.amqp.client")
public class ClientApplication {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ClientApplication.class);

        RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);

        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
        messageProperties.setContentType("UTF-8");
        Message message = new Message("订单信息".getBytes(), messageProperties);
        // 如果超时未返回 则messageReturn为null 可以通过rabbitTemplate.setReplyTimeout(10000);设置超时时间
        Object messageReturn = rabbitTemplate.sendAndReceive("roberto.order", "add", message, new CorrelationData("201210704116"));
        System.out.println(messageReturn);
    }
}

6.依次调用查看客户端控制台输出

订单ID

猜你喜欢

转载自blog.csdn.net/RobertoHuang/article/details/79616581