文章目录
前言
RabbitMQ是一个由Erlang语言编写的、开源的、在AMQP基础上完整的、可复用的企业消息系统。在上个项目中使用到了RabbitMQ进行消息的投递,本篇文章主要介绍下RabbitMQ在SpingBoot项目中的简单整合和在Docker中运行RabbitMQ容器的步骤。
一、Docker运行RabbitMQ
RabbitMQ依赖Erlang环境,在Linux系统上安装Erlang和RabbitMQ会比较麻烦,这里介绍下用Docker部署的步骤
1. 搜索和拉取RabbitMQ镜像
# 搜索
docker search rabbitmq
# 拉取镜像
docker pull rabbitmq:3.8.2
2. 创建 rabbitmq 容器,并设置开机启动
docker run -it -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.8.2-management
docker update rabbitmq --restart=always
通过服务器地址访问端口号为15672,账号密码为guest
二、导入RabbitMQ依赖库
在 pom.xml 中添加依赖
<!--rabbitmq依赖-->
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
三、创建RabbitMQ配置类
连接 RabbitMQ 需要用到 ConnectionFactory ,所以我们要自己创建好 ConnectionFactory 对象然后注册给Spring框架,创建 RabbitMQConfig 配置类
@Configuration
public class RabbitMQConfig {
@Bean
public ConnectionFactory getFactory(){
ConnectionFactory factory=new ConnectionFactory();
factory.setHost("xxx.xxx.xxx.xxx");//主机地址
factory.setPort(5672);//客户端连接端口号
return factory;
}
}
四、创建消息接收和发送所需的实体类
/**
* 消息发送实体
*/
@Data
@Document(collection = "message")
public class MessageEntity implements Serializable {
@Id
private String _id;
@Indexed(unique = true)
private String uuid;
@Indexed
private Integer senderId;
private String senderPhoto = "";
private String senderName;
private String msg;
@Indexed
private Date sendTime;
}
/**
* 消息接收实体
*/
@Data
@Document(collection = "message_ref")
public class MessageRefEntity implements Serializable {
@Id
private String _id;
@Indexed
private String messageId;
@Indexed
private Integer receiverId;
@Indexed
private Boolean readFlag;
@Indexed
private Boolean lastFlag;
}
五、创建消息任务类
创建 MessageTask ,并编写同步/异步发送消息方法,通过调用这个类中的方法进行消息的发送和接收等操作
@Component
@Slf4j
public class MessageTask {
@Autowired
private ConnectionFactory factory;
@Autowired
private MessageService messageService;
/**
* 消息发送
* @param topic
* @param entity
*/
public void send(String topic, MessageEntity entity) {
String id = messageService.insertMessage(entity);
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
) {
channel.queueDeclare(topic, true, false, false, null);
HashMap map = new HashMap();
map.put("messageId", id);
AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().headers(map).build();
channel.basicPublish("", topic, properties, entity.getMsg().getBytes());
log.debug("消息发送成功!");
} catch (Exception e) {
log.error("执行异常", e);
throw new TeamsException("向MQ发送消息失败");
}
}
/**
* 异步消息发送
* @param topic
* @param entity
*/
@Async
public void sendAsync(String topic, MessageEntity entity) {
send(topic, entity);
}
/**
* 消息接收
* @param topic
* @return
*/
public Integer receive(String topic) {
int i = 0;
// 获取链接
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
) {
channel.queueDeclare(topic, true, false, false, null);
while (true) {
GetResponse response = channel.basicGet(topic, false);
if (response != null) {
AMQP.BasicProperties properties = response.getProps();
Map<String, Object> map = properties.getHeaders();
String messageId = map.get("messageId").toString();
byte[] body = response.getBody();
String message = new String(body);
log.debug("从RabbitMQ接收的消息:" + message);
MessageRefEntity entity = new MessageRefEntity();
entity.setMessageId(messageId);
entity.setReceiverId(Integer.parseInt(topic));
entity.setReadFlag(false);
entity.setLastFlag(true);
messageService.insertRef(entity);
long deliveryTag = response.getEnvelope().getDeliveryTag();
channel.basicAck(deliveryTag, false);
i++;
} else {
break;
}
}
} catch (Exception e) {
log.error("执行异常", e);
throw new TeamsException("接收消息失败");
}
return i;
}
/**
* 异步消息接收
* @param topic
* @return
*/
@Async
public Integer receiveAsync(String topic) {
return receive(topic);
}
/**
* 删除消息队列
* @param topic
*/
public void deleteQueue(String topic) {
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
) {
channel.queueDelete(topic);
log.debug("消息队列成功删除");
} catch (Exception e) {
log.error("删除队列失败", e);
throw new TeamsException("删除队列失败");
}
}
/**
* 异步删除消息队列
* @param topic
*/
@Async
public void deleteQueueAsync(String topic) {
deleteQueue(topic);
}
}
总结
以上就是今天要讲的内容,本文仅仅简单介绍了RabbitMQ的使用,RabbitMQ还有多种队列模式,需要了解更多可以参考官方文档。