本系列博客源码GIT地址:https://github.com/RobertoHuang/RGP-RABBITMQ.git
服务端步骤:
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 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进行异步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端配置类
@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 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 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 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