SpringBoot集成RabbitMq简单应用
- maven配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
- application配置文件
#####rabbitmq####
spring.application.name=springboot-rabbitmq
spring.rabbitmq.addresses=*****
spring.rabbitmq.port=5672
spring.rabbitmq.username=****
spring.rabbitmq.password=****
spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.publisher-returns=true
spring.rabbitmq.virtual-host=/
spring.rabbitmq.queue.prefix.name=lyh-test
#采用手動應答
spring.rabbitmq.listener.simple.acknowledge-mode=MANUAL
spring.rabbitmq.listener.simple.retry.enabled=true
logging.level.root=info
- 启动类
package com.lyh.mq;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MqApplication {
public static void main(String[] args) {
SpringApplication.run(MqApplication.class, args);
}
}
-
Exchange 类型
Exchange分发消息时根据类型的不同分发策略有区别,目前共四种类型:direct、fanout、topic、headers 。下面只讲前三种模式。
1.Direct模式
消息中的路由键(routing key)如果和 Binding 中的 binding key 一致, 交换器就将消息发到对应的队列中。路由键与队列名完全匹配
2.Topic模式
topic 交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上。它将路由键和绑定键的字符串切分成单词,这些单词之间用点隔开。它同样也会识别两个通配符:符号“#”和符号“*”。#匹配0个或多个单词,*匹配一个单词。
3.Fanout模式
每个发到 fanout 类型交换器的消息都会分到所有绑定的队列上去。fanout 交换器不处理路由键,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。fanout 类型转发消息是最快的。
-
路由模式--direct
1:队列配置类
package com.lyh.mq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
@Configuration
public class MqConfig {
private static Logger log = LoggerFactory.getLogger(MqConfig.class);
@Resource
RabbitTemplate rabbitTemplate;
@Bean
public AmqpTemplate amqpTemplate() {
// 使用jackson 消息转换器
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
rabbitTemplate.setEncoding("UTF-8");
// 开启returncallback yml 需要 配置 publisher-returns: true
rabbitTemplate.setMandatory(true);
// rabbitTemplate.setConnectionFactory(new CachingConnectionFactory());
rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
String correlationId = message.getMessageProperties().getCorrelationId();
log.error("消息:{} 发送失败, 应答码:{} 原因:{} 交换机: {} 路由键: {}", correlationId, replyCode, replyText, exchange, routingKey);
});
// 消息确认 yml 需要配置 publisher-returns: true
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if (ack) {
log.debug("消息发送到exchange成功,id: {}", correlationData.getId());
} else {
log.error("消息发送到exchange失败,原因: {}", cause);
}
});
return rabbitTemplate;
}
//TODO:基本消息模型构建
@Bean
public DirectExchange basicExchange(){
return new DirectExchange("basicExchange", true,false);
}
@Bean(name = "basicQueue")
public Queue basicQueue(){
return new Queue("basicQueue", true);
}
@Bean
public Binding basicBinding(){
return BindingBuilder.bind(basicQueue()).to(basicExchange()).with("basicKey");
}
}
2:发送者类
package com.lyh.mq;
import com.alibaba.fastjson.JSONObject;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
@RestController
public class RabbitProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
@RequestMapping("directSend")
public void directSend() {
Date date = new Date();
String dateString = new SimpleDateFormat("YYYY-mm-DD hh:MM:ss").format(date);
System.out.println("[string] send msg:" + dateString);
// 第一个参数为刚刚定义的队列名称
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplate.convertAndSend("basicExchange","basicKey",dateString,correlationData);
}
}
3:接收者类
package com.lyh.mq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Service;
@Service
public class RabbitConsumer {
private static final Logger log= LoggerFactory.getLogger(RabbitConsumer.class);
/**
* 监听消费消息
* @param message
*/
@RabbitListener(queues ="basicQueue")
public void consumeMessage(@Payload byte[] message){
try {
//TODO:接收String
String result=new String(message,"UTF-8");
log.info("接收String消息: {} ",result);
}catch (Exception e){
log.error("监听消费消息 发生异常: ",e.fillInStackTrace());
}
}
}
4:访问http://localhost:8080/directSend,查看日志输出
INFO 8772 --- [io-8080-exec-10] com.lzc.rabbitmq.config.Sender : 【sendDirectQueue已发送消息】
INFO 8772 --- [cTaskExecutor-1] com.lzc.rabbitmq.config.Receiver : 【receiverDirectQueue监听到消息】User(userId=123456, name=lizhencheng)
注意:发送者与接收者的Queue名字一定要相同,否则接收收不到消息
-
Fanout模式
1:队列配置类
package com.lyh.mq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
@Configuration
public class MqConfig {
private static Logger log = LoggerFactory.getLogger(MqConfig.class);
@Resource
RabbitTemplate rabbitTemplate;
@Bean
public AmqpTemplate amqpTemplate() {
// 使用jackson 消息转换器
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
rabbitTemplate.setEncoding("UTF-8");
// 开启returncallback yml 需要 配置 publisher-returns: true
rabbitTemplate.setMandatory(true);
// rabbitTemplate.setConnectionFactory(new CachingConnectionFactory());
rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
String correlationId = message.getMessageProperties().getCorrelationId();
log.error("消息:{} 发送失败, 应答码:{} 原因:{} 交换机: {} 路由键: {}", correlationId, replyCode, replyText, exchange, routingKey);
});
// 消息确认 yml 需要配置 publisher-returns: true
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if (ack) {
log.debug("消息发送到exchange成功,id: {}", correlationData.getId());
} else {
log.error("消息发送到exchange失败,原因: {}", cause);
}
});
return rabbitTemplate;
}
//TODO:基本消息模型构建
@Bean
public DirectExchange basicExchange(){
return new DirectExchange("basicExchange", true,false);
}
@Bean(name = "basicQueue")
public Queue basicQueue(){
return new Queue("basicQueue", true);
}
@Bean
public Binding basicBinding(){
return BindingBuilder.bind(basicQueue()).to(basicExchange()).with("basicKey");
}
@Bean("fanoutExchange")
public FanoutExchange fanoutExchange() {
return new FanoutExchange("fanoutExchange",true,false);
}
@Bean("fanout01")
public Queue fanout01(){
return QueueBuilder.durable("fanout01").build();
}
@Bean("fanout02")
public Queue fanout02(){
return QueueBuilder.durable("fanout02").build();
}
@Bean
public Binding fanoutBind01(){
return BindingBuilder.bind(fanout01()).to(fanoutExchange());
}
@Bean
public Binding fanoutBind012(){
return BindingBuilder.bind(fanout02()).to(fanoutExchange());
}
}
2:发送者类
package com.lyh.mq;
import com.alibaba.fastjson.JSONObject;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
@RestController
public class RabbitProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
@RequestMapping("directSend")
public void directSend() {
Date date = new Date();
String dateString = new SimpleDateFormat("YYYY-mm-DD hh:MM:ss").format(date);
System.out.println("[string] send msg:" + dateString);
// 第一个参数为刚刚定义的队列名称
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplate.convertAndSend("basicExchange","basicKey",dateString,correlationData);
}
@RequestMapping("fanoutSend")
public void fanoutSend() {
Date date = new Date();
String dateString = new SimpleDateFormat("YYYY-mm-DD hh:MM:ss").format(date);
System.out.println("[string] send msg:" + dateString);
// 第一个参数为刚刚定义的队列名称
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplate.convertAndSend("fanoutExchange","",dateString,correlationData);
}
}
3:接收者类
package com.lyh.mq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Service;
@Service
public class RabbitConsumer {
private static final Logger log= LoggerFactory.getLogger(RabbitConsumer.class);
/**
* 监听消费消息
* @param message
*/
@RabbitListener(queues ="basicQueue")
public void consumeMessage(@Payload byte[] message){
try {
//TODO:接收String
String result=new String(message,"UTF-8");
log.info("接收String消息: {} ",result);
}catch (Exception e){
log.error("监听消费消息 发生异常: ",e.fillInStackTrace());
}
}
/**
* 监听消费消息
* @param message
*/
@RabbitListener(queues ="fanout01")
public void consumeMessage1(@Payload byte[] message){
try {
//TODO:接收String
String result=new String(message,"UTF-8");
log.info("接收String1消息: {} ",result);
}catch (Exception e){
log.error("监听消费消息 发生异常: ",e.fillInStackTrace());
}
}
/**
* 监听消费消息
* @param message
*/
@RabbitListener(queues ="fanout02")
public void consumeMessage2(@Payload byte[] message){
try {
//TODO:接收String
String result=new String(message,"UTF-8");
log.info("接收String2消息: {} ",result);
}catch (Exception e){
log.error("监听消费消息 发生异常: ",e.fillInStackTrace());
}
}
}
4:访问http://localhost:8080/fanoutSend
查看日志输出,由日志输出可以看出,两个接收者都接收到了消息,因为交换机fanoutExchange绑定了两个队列。
-
Topic模式
1:队列配置类
package com.lyh.mq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
@Configuration
public class MqConfig {
private static Logger log = LoggerFactory.getLogger(MqConfig.class);
@Resource
RabbitTemplate rabbitTemplate;
@Bean
public AmqpTemplate amqpTemplate() {
// 使用jackson 消息转换器
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
rabbitTemplate.setEncoding("UTF-8");
// 开启returncallback yml 需要 配置 publisher-returns: true
rabbitTemplate.setMandatory(true);
// rabbitTemplate.setConnectionFactory(new CachingConnectionFactory());
rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
String correlationId = message.getMessageProperties().getCorrelationId();
log.error("消息:{} 发送失败, 应答码:{} 原因:{} 交换机: {} 路由键: {}", correlationId, replyCode, replyText, exchange, routingKey);
});
// 消息确认 yml 需要配置 publisher-returns: true
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if (ack) {
log.debug("消息发送到exchange成功,id: {}", correlationData.getId());
} else {
log.error("消息发送到exchange失败,原因: {}", cause);
}
});
return rabbitTemplate;
}
//TODO:基本消息模型构建
@Bean
public DirectExchange basicExchange(){
return new DirectExchange("basicExchange", true,false);
}
@Bean(name = "basicQueue")
public Queue basicQueue(){
return new Queue("basicQueue", true);
}
@Bean
public Binding basicBinding(){
return BindingBuilder.bind(basicQueue()).to(basicExchange()).with("basicKey");
}
@Bean("fanoutExchange")
public FanoutExchange fanoutExchange() {
return new FanoutExchange("fanoutExchange",true,false);
}
@Bean("fanout01")
public Queue fanout01(){
return QueueBuilder.durable("fanout01").build();
}
@Bean("fanout02")
public Queue fanout02(){
return QueueBuilder.durable("fanout02").build();
}
@Bean
public Binding fanoutBind01(){
return BindingBuilder.bind(fanout01()).to(fanoutExchange());
}
@Bean
public Binding fanoutBind012(){
return BindingBuilder.bind(fanout02()).to(fanoutExchange());
}
/**
* Topic模式
* @return
*/
public static final String TOPIC_QUEUE1 = "topic.queue1";
public static final String TOPIC_QUEUE2 = "topic.queue2";
public static final String TOPIC_EXCHANGE = "topic.exchange";
@Bean
public Queue topicQueue1() {
return new Queue(TOPIC_QUEUE1);
}
@Bean
public Queue topicQueue2() {
return new Queue(TOPIC_QUEUE2);
}
@Bean
public TopicExchange topicExchange() {
return new TopicExchange(TOPIC_EXCHANGE);
}
@Bean
public Binding topicBinding1() {
return BindingBuilder.bind(topicQueue1()).to(topicExchange()).with("lzc.message");
}
@Bean
public Binding topicBinding2() {
return BindingBuilder.bind(topicQueue2()).to(topicExchange()).with("lzc.#");
}
}
2:发送者类
package com.lyh.mq;
import com.alibaba.fastjson.JSONObject;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
@RestController
public class RabbitProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
@RequestMapping("directSend")
public void directSend() {
Date date = new Date();
String dateString = new SimpleDateFormat("YYYY-mm-DD hh:MM:ss").format(date);
System.out.println("[string] send msg:" + dateString);
// 第一个参数为刚刚定义的队列名称
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplate.convertAndSend("basicExchange","basicKey",dateString,correlationData);
}
@RequestMapping("fanoutSend")
public void fanoutSend() {
Date date = new Date();
String dateString = new SimpleDateFormat("YYYY-mm-DD hh:MM:ss").format(date);
System.out.println("[string] send msg:" + dateString);
// 第一个参数为刚刚定义的队列名称
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplate.convertAndSend("fanoutExchange","",dateString,correlationData);
}
@RequestMapping("sendTopic")
public void sendTopic() {
Date date = new Date();
String dateString = new SimpleDateFormat("YYYY-mm-DD hh:MM:ss").format(date);
System.out.println("[string] send msg:" + dateString);
// 第一个参数为刚刚定义的队列名称
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
this.rabbitTemplate.convertAndSend(MqConfig.TOPIC_EXCHANGE, "lzc.message", dateString );
this.rabbitTemplate.convertAndSend(MqConfig.TOPIC_EXCHANGE, "lzc.lzc", dateString);
}
}
3:接收者类
package com.lyh.mq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Service;
@Service
public class RabbitConsumer {
private static final Logger log= LoggerFactory.getLogger(RabbitConsumer.class);
/**
* 监听消费消息
* @param message
*/
@RabbitListener(queues ="basicQueue")
public void consumeMessage(@Payload byte[] message){
try {
//TODO:接收String
String result=new String(message,"UTF-8");
log.info("接收String消息: {} ",result);
}catch (Exception e){
log.error("监听消费消息 发生异常: ",e.fillInStackTrace());
}
}
/**
* 监听消费消息
* @param message
*/
@RabbitListener(queues ="fanout01")
public void consumeMessage1(@Payload byte[] message){
try {
//TODO:接收String
String result=new String(message,"UTF-8");
log.info("接收String1消息: {} ",result);
}catch (Exception e){
log.error("监听消费消息 发生异常: ",e.fillInStackTrace());
}
}
/**
* 监听消费消息
* @param message
*/
@RabbitListener(queues ="fanout02")
public void consumeMessage2(@Payload byte[] message){
try {
//TODO:接收String
String result=new String(message,"UTF-8");
log.info("接收String2消息: {} ",result);
}catch (Exception e){
log.error("监听消费消息 发生异常: ",e.fillInStackTrace());
}
}
@RabbitListener(queues = MqConfig.TOPIC_QUEUE1)
public void receiveTopic1(@Payload byte[] message) {
log.info("【receiveTopic1监听到消息】" + message.toString());
}
@RabbitListener(queues = MqConfig.TOPIC_QUEUE2)
public void receiveTopic2(@Payload byte[] message) {
log.info("【receiveTopic2监听到消息】" + message.toString());
}
}
4:访问http://localhost:8080/sendTopic
查看日志输出,由日志记录可以看出lzc.message可以被receiveTopic1和receiveTopic2所接收,而lzc.lzc只能被receiveTopic2接收。