之前用GO写过RabbitMQ相关的服务,已经装了RabbitMQ和Erlang,跳过安装步骤。
(记得当时用go写的时候没这么麻烦呀,像什么Exchanges、Queues之类的概念我都不知道,写出来了也能跑通)
Erlang配置系统环境变量
Path中新增%ERLANG_HOME%\bin
系统变量中新增D:\programfiles\Erlang OTP
(改为自己的Erlang安装地址)
cmd测试配置成功
启动RabbitMQ服务
rabbitmq-plugins enable rabbitmq_management
启用管理插件用户界面
rabbitmq-server start
启动服务
http://localhost:15672/
进入用户界面
默认账号密码都是guest(guest:guest)
查看所有用户
bash
server.port=8080
#这几个是默认配置。 不配也行。
#spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.addresses=42.192.145.166
spring.rabbitmq.virtual-host=/
#spring.rabbitmq.addresses=172.16.48.10:5672,172.16.48.11:5672,172.16.48.12:5672
生产者
java
@CrossOrigin
@RestController
@RequestMapping("/api/chat")
public class ChatController {
@Resource
private RabbitTemplate rabbitTemplate;
@GetMapping(value="/send")
public int helloWorldSend() throws UnsupportedEncodingException {
// 队列名称
String queueName = "chat";
// 消息
String message = "你好啊, rabbitmq!";
rabbitTemplate.convertAndSend(queueName,message);
return 1;
}
}
消费者
bash
@Component
public class Consumer {
// 获取那个消息队列 消息队列的名称
@RabbitListener(queues = "chat")
public void listenSimpleQueueMessage(String message) {
//
System.out.println("spring 消费者接收到的消息是:"+message);
}
}
也可以直接将生产者和消费者写在一个Controller中
java
@CrossOrigin
@RestController
@RequestMapping("/api/chat")
public class ChatController {
@Resource
private RabbitTemplate rabbitTemplate;
@GetMapping(value="/send")
public int Send() {
// 队列名称
String queueName = "chat";
for (int i = 0; i < 10; i++) {
// 生产者发送消息
rabbitTemplate.convertAndSend(queueName, "spring boot 发送消息" + i);
}
return 1;
}
// 消费者
@RabbitListener(queues = "chat")
public void listenSimpleQueueMessage(String message) {
System.out.println("spring 消费者接收到的消息是:"+message);
// 暂停1秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
此时报错Failed to declare queue(s):[chat]
原因是消费者监听的队列还没有被创造,需要先手动新建一个队列。
先在Test中创建消息队列(在此之前把消费者注释掉)
java
@Test
public void testSendMessage() throws IOException, TimeoutException {
// 1.建立连接
ConnectionFactory factory = new ConnectionFactory();
// 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
factory.setHost("localhost");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("guest");
factory.setPassword("guest");
// 1.2.建立连接
Connection connection = factory.newConnection();
// 2.创建通道Channel
Channel channel = connection.createChannel();
// 3.创建队列
String queueName = "chat";
channel.queueDeclare(queueName, false, false, false, null);
// 4.发送消息
String message = "hello, rabbitmq!";
channel.basicPublish("", queueName, null, message.getBytes());
System.out.println("发送消息成功:【" + message + "】");
// 5.关闭通道和连接
channel.close();
connection.close();
}
}
输出
一些尝试
RabbitMQ tutorial - Remote procedure call (RPC)
通过spring提供的一个RabbitTemplate对象中sendAndReceiverabbitTemplate.sendAndReceive
方法来实现,这个方法是发送消息然后一直等待响应。监听器里面实现的和之前的逻辑大致相同,都需要将response响应消息发送到对应的replyTo回调队列上。(这跟远程方法调用有什么关系?)
我感觉在我想实现RPC的功能不太一样。
最终还是用自己写的一个简单的RPC来实现远程方法调用。
RPC消费者将远程调用的函数名和函数参数通过http发送给服务提供者。RPC服务提供者通过Tomcat接收远程方法调用,处理后将结果返回给调用者。
RPC消费者(也就是主要业务代码)的Controller层接收消息后将其绑定一个ID放入RabbitMQ中,并将ID返回给用户,告诉用户收到请求,正在处理。用户通过ID不断请求实际处理后的结果。同时RabbitMQ的消费者(也属于RPC消费者代码中)从RabbitMQ中获取请求,通过RPC向远程方法调用的服务提供者发送请求,收到返回结果后,将结果存入数据库,再从RabbitMQ中拉取下一条请求。
保证RPC服务提供者同一时刻只会处理一条消息,防止请求消息丢失。