pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wuychn</groupId>
<artifactId>springboot-rabbitmq</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot-rabbitmq</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- rabbitmq依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml:
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
# 消息发送到交换器确认机制,是否确认回调
publisher-confirms: true
publisher-returns: true
server:
port: 8080
交换器配置类ExchangeConfig:
package com.wuychn.springbootrabbitmq.config;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ExchangeConfig {
public static final String EXCHANGE_NAME = "exchange";
@Bean
public DirectExchange directExchange() {
// 参数依次是交换器名称、是否持久化、是否自动删除
return new DirectExchange(EXCHANGE_NAME, true, false);
}
}
队列配置类QueueConfig:
package com.wuychn.springbootrabbitmq.config;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QueueConfig {
// 队列1的名称
public static final String QUEUE_NAME_1 = "queue1";
// 队列2的名称
public static final String QUEUE_NAME_2 = "queue2";
@Bean
public Queue queue1() {
// 参数依次为:队列名称,是否持久化,是否排他,是否自动删除
return new Queue(QUEUE_NAME_1, true, false, false);
}
@Bean
public Queue queue2() {
// 参数依次为:队列名称,是否持久化,是否排他,是否自动删除
return new Queue(QUEUE_NAME_2, true, false, false);
}
}
RabbitMQ配置类RabbitMqConfig:
package com.wuychn.springbootrabbitmq.config;
import com.wuychn.springbootrabbitmq.callback.MsgSendConfirmCallBack;
import com.wuychn.springbootrabbitmq.callback.MsgSendReturnCallback;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMqConfig {
@Value("${spring.rabbitmq.host}")
public String host;
@Value("${spring.rabbitmq.port}")
public int port;
@Value("${spring.rabbitmq.username}")
public String username;
@Value("${spring.rabbitmq.password}")
public String password;
// 路由键1
public static final String ROUTING_KEY_1 = "routingKey1";
// 路由键2
public static final String ROUTING_KEY_2 = "routingKey2";
@Autowired
public QueueConfig queueConfig;
@Autowired
public ExchangeConfig exchangeConfig;
// @Autowired
// private ConnectionFactory connectionFactory;
/**
* ConnectionFactory,可以直接注入,如上
*
* @return
*/
//@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host, port);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
connectionFactory.setVirtualHost("/");
connectionFactory.setPublisherConfirms(true);
return connectionFactory;
}
/**
* 将消息队列1和交换器绑定
*
* @return
*/
@Bean
public Binding binding1() {
return BindingBuilder.bind(queueConfig.queue1()).to(exchangeConfig.directExchange()).with(RabbitMqConfig.ROUTING_KEY_1);
}
/**
* 将消息队列2和交换器绑定
*
* @return
*/
@Bean
public Binding binding2() {
return BindingBuilder.bind(queueConfig.queue2()).to(exchangeConfig.directExchange()).with(RabbitMqConfig.ROUTING_KEY_2);
}
/**
* 自定义rabbitTemplate用于数据的接收和发送
* 可以设置消息确认机制和回调
*
* @return
*/
@Bean
public RabbitTemplate rabbitTemplate() {
RabbitTemplate template = new RabbitTemplate(connectionFactory());
// 可以自定义消息转换器,默认使用的JDK的,所以消息对象需要实现Serializable
// template.setMessageConverter();
// 若使用 confirm-callback 或 return-callback,
// 必须要配置 publisherConfirms 或 publisherReturns为true
// 每个 rabbitTemplate 只能有一个confirm-callback和return-callback
template.setConfirmCallback(msgSendConfirmCallBack());
// 使用 return-callback 时必须设置 mandatory 为true
// 或者在配置中设置 mandatory-expression 的值为true
// 可针对每次请求的消息去确定 mandatory 的 boolean 值
// 只能在提供 return-callback 时使用,与 mandatory 互斥
// 关于 msgSendConfirmCallBack 和 msgSendReturnCallback 的回调说明:
// 1、如果消息没有到 exchange,则 confirm 回调, ack=false
// 2、如果消息到达 exchange, 则 confirm 回调, ack=true
// 3、exchange到queue成功, 则不回调return
// 4、exchange到queue失败, 则回调return(需设置mandatory=true, 否则不会回调, 消息就丢了)
template.setReturnCallback(msgSendReturnCallback());
template.setMandatory(true);
return template;
}
/**
* 消息确认机制
*
* @return
*/
@Bean
public MsgSendConfirmCallBack msgSendConfirmCallBack() {
return new MsgSendConfirmCallBack();
}
@Bean
public MsgSendReturnCallback msgSendReturnCallback() {
return new MsgSendReturnCallback();
}
}
MsgSendConfirmCallBack:
package com.wuychn.springbootrabbitmq.callback;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
public class MsgSendConfirmCallBack implements RabbitTemplate.ConfirmCallback {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
System.out.println("消息发送回调:" + correlationData);
if (ack) {
System.out.println("消息发送成功");
} else {
System.out.println("消息发送失败:" + cause + "\n重新发送");
}
}
}
MsgSendReturnCallback:
package com.wuychn.springbootrabbitmq.callback;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
public class MsgSendReturnCallback implements RabbitTemplate.ReturnCallback {
// 消息如到达了队列不会回调,只有没有到达队列才会回调这个方法,所以不像 confirm 的回调需要判断是否成功
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
System.out.println("回馈消息:" + message);
}
}
Producer1:
package com.wuychn.springbootrabbitmq.producer;
import com.wuychn.springbootrabbitmq.config.ExchangeConfig;
import com.wuychn.springbootrabbitmq.config.RabbitMqConfig;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Producer1 {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 发送消息
*
* @param uuid
* @param message 消息
*/
public void send(String uuid, Object message) {
CorrelationData correlationId = new CorrelationData(uuid);
rabbitTemplate.convertAndSend(ExchangeConfig.EXCHANGE_NAME, RabbitMqConfig.ROUTING_KEY_1,
message, correlationId);
}
}
Producer2:
package com.wuychn.springbootrabbitmq.producer;
import com.wuychn.springbootrabbitmq.config.ExchangeConfig;
import com.wuychn.springbootrabbitmq.config.RabbitMqConfig;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Producer2 {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 发送消息
*
* @param uuid
* @param message 消息
*/
public void send(String uuid, Object message) {
CorrelationData correlationId = new CorrelationData(uuid);
rabbitTemplate.convertAndSend(ExchangeConfig.EXCHANGE_NAME, RabbitMqConfig.ROUTING_KEY_2,
message, correlationId);
}
}
Consumer1:
package com.wuychn.springbootrabbitmq.consumer;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class Consumer1 {
/**
* 指定从哪个队列订阅消息,可以指定多个,用逗号隔开
*
* @param message
*/
@RabbitListener(queues = {"queue1"})
public void handleMessage(String message) {
// 处理消息
System.out.println("consumer1收到消息:" + message);
}
}
Consumer2:
package com.wuychn.springbootrabbitmq.consumer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* 指定从哪个队列订阅消息,可以指定多个,用逗号隔开
* 注意,和Consumer1不同,这里的@RabbitListener是写在类上的
* 在具体的处理方法上需要再加一个@RabbitHandler注解
*/
@Component
@RabbitListener(queues = {"queue2"})
public class Consumer2 {
/**
* 处理接收到的消息
*
* @param message
*/
@RabbitHandler
public void handleMessage(String message) {
// 处理消息
System.out.println("consumer2收到消息:" + message);
}
}
MsgController:
package com.wuychn.springbootrabbitmq.controller;
import com.wuychn.springbootrabbitmq.producer.Producer1;
import com.wuychn.springbootrabbitmq.producer.Producer2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
@RestController
public class MsgController {
@Autowired
private Producer1 producer1;
@Autowired
private Producer2 producer2;
@GetMapping("/send1")
public String send1(String msg) {
String uuid = UUID.randomUUID().toString();
producer1.send(uuid, msg);
return uuid;
}
@GetMapping("/send2")
public String send2(String msg) {
String uuid = UUID.randomUUID().toString();
producer2.send(uuid, msg);
return uuid;
}
}
项目结构:
参考: