rabbitmq消息队列简介以及相关demo示例

RabbitMQ是使用Erlang语言开发的开源消息队列系统,基于AMQP协议来实现。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、 安全。AMQP协议更多用在企业系统内,对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求还在其次。

以下为rabbitmq工作的简单示意图:

 

其中每个角色的含义如下:

  • publisher:生产者
  • consumer:消费者
  • exchange:交换机,负责消息路由
  • queue:队列,存储消息
  • virtualHost:虚拟主机,隔离不同租户的 exchange、queue、消息的隔离

rabbitmq通常有5种工作模型:

  • 简单队列
  • Work模式
  • 广播模式
  • 路由模式(生产者发布消息携带路由key,发送到指定的交换机,交换机再在与其绑定的队列中通过路由key辨别出符合规定的队列,发送消息)
  • 主题模式(通配符模式)

其中以常用的路由模式在java中如何实现进行讲解如下:

第一步:由于rabbitmq是Erlang语言编写的首先应该配置Erlang语言环境:官网下载安装包,配置环境变量,dos窗口使用'erl'命令显示版本号即安装成功;

第二步:下载rabbitmq安装,配置环境变量;

第三步:引入依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.6.4</version>
</dependency>
第四步:配置yml中关于mq的配置
spring:
rabbitmq:
host: localhost #rabbitmq所在主机ip
port: 5672 #默认端口
username: guest #登录用户名
password: guest #登录密码
virtual-host: / #虚拟主机(即mini-RabbitMQ server)
listener:
simple:
prefetch: 1 #每次只能获取一条消息,处理完成才能获取下一个
publisher-confirm-type: correlated
publisher-returns: true
template:
mandatory: true

 第五步:rabbitmq配置类编写(定义交换机、队列、和他们的绑定关系方便代码使用,当然也可以视情况在具体代码中去定义他们)

package com.feng.util;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* @author sun
* @since 1.0.0
*/
@Configuration
public class RabbitMQConfig {
private static final String QUEUE01 = "queue_direct01";
private static final String QUEUE02 = "queue_direct02";
private static final String EXCHANGE = "directExchange";
private static final String ROUTINGKEY01 = "queue.red";
private static final String ROUTINGKEY02 = "queue.green";

@Bean
public Queue queue01() {
return new Queue(QUEUE01);
}

@Bean
public Queue queue02() {
return new Queue(QUEUE02);
}

@Bean
public DirectExchange directExchange() {
return new DirectExchange(EXCHANGE);
}

@Bean
public Binding binding01() {
return BindingBuilder.bind(queue01()).to(directExchange()).with(ROUTINGKEY01);
}

@Bean
public Binding binding02() {
return BindingBuilder.bind(queue02()).to(directExchange()).with(ROUTINGKEY02);
}

@Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}

// 使用下面的配置的话就不需要yml中配置mq的信息,不用下面的代码就需要在yml中配置mq的信息,启动程序的时候会自动加载yml中的配置封装mq对象并连接mq
/*@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setHost("localhost");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setVirtualHost("/");
connectionFactory.setConnectionTimeout(15000);
// 如果要进行消息回调,则这里必须要设置为true
connectionFactory.setPublisherConfirms(true);
connectionFactory.setPublisherReturns(true);
return connectionFactory;
}*/

/**
* 设置返回回调和确认回调
*
* @param connectionFactory
* @return
*/
/* @Bean
RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, RabbitMQConfirmAndReturn rabbitMQConfirmAndReturn) {
RabbitTemplate rabbitTemplate = new RabbitTemplate();
rabbitTemplate.setConnectionFactory(connectionFactory);
rabbitTemplate.setConfirmCallback(rabbitMQConfirmAndReturn);
rabbitTemplate.setReturnCallback(rabbitMQConfirmAndReturn);
rabbitTemplate.setEncoding("UTF-8");
//Mandatory为true时,消息通过交换器无法匹配到队列会返回给生产者,为false时匹配不到会直接被丢弃
rabbitTemplate.setMandatory(true);
rabbitTemplate.setMessageConverter(jsonMessageConverter());
return rabbitTemplate;
}*/
}

第六步:编写消息confirm/return机制
package com.feng.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class RabbitMQConfirmAndReturn implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback {

/**
* Return 消息机制用于处理一个不可路由的消息。在某些情况下,如果我们在发送消息的时候,当前的 exchange 不存在或者指定路由 key 路由不到,这个时候我们需要监听这种不可达的消息
* 就需要这种return机制
* @param message
* @param replyCode
* @param replyText
* @param exchange
* @param routingKey
*/
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
log.info("mq消息不可达,message:{},replyCode:{},replyText:{},exchange:{},routing:{}", message.toString(), replyCode, replyText, exchange, routingKey);
String messageId = message.getMessageProperties().getMessageId();
}

/**
* confirm机制只保证消息到达exchange,不保证消息可以路由到正确的queue,如果exchange错误,就会触发confirm机制
*
* @param correlationData
* @param b
* @param s
*/
@Override
public void confirm(CorrelationData correlationData, boolean b, String s) {
if (!b) {
log.info("rabbitmq confirm fail,cause:{}", s);
}else {
log.info("rabbitmq confirm success,cause:{}", s);
}
}
}

第七步:封装消息发送类,amqp中封装了RabbitTemplate模板,使用rabbitTemplate.convertAndSend就能进行消息的发送
package com.feng.util;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
* @Author sun
* @Date 2023/5/10 9:30
*/
@Service
public class SendMessage {

@Autowired
private RabbitTemplate rabbitTemplate;

@Autowired
private RabbitMQConfirmAndReturn rabbitMQConfirmAndReturn;

public void testMessage(String msg) {
// 设置交换机处理失败消息的模式 true表示消息由交换机到达不了队列时,会将消息重新返回给生产者
// 如果不是指该指令,那么交换机向队列推送失败后不会触发setReturnCallBack
rabbitTemplate.setMandatory(true);
// 消息消费者确认收到消息后,手动back回执
rabbitTemplate.setConfirmCallback(rabbitMQConfirmAndReturn);
rabbitTemplate.setReturnCallback(rabbitMQConfirmAndReturn);
rabbitTemplate.convertAndSend("directExchange", "queue.red", msg);
}
}

第八步:编写消息消费类:其中注解 @RabbitListener(queues = "queue_direct01")既可以监听指定队列的消息进行消费
package com.feng.util;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;

/**
* @Author sun
* @Date 2023/5/9 17:30
*/
@Service
public class MessageListener {

@RabbitListener(queues = "queue_direct01")
public void myListener(String message) {
System.out.println("接收的消息为:" + message);
}
}

至此一个简单的demo得以实现。

posted @ 2023-05-11 11:18  一剑一叶一花  阅读(187)  评论(0编辑  收藏  举报