org.springframework.boot
spring-boot-starter
2.1.3.RELEASE
org.springframework.boot
spring-boot-starter-amqp
com.fasterxml.jackson.core
jackson-databind
2.9.8
org.springframework.boot
spring-boot-starter-test
spring.application.name=rabbitmq-demo
server.port=8080
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
# 开启发送确认
spring.rabbitmq.publisher-confirms=true
# 开启发送失败退回
spring.rabbitmq.publisher-returns=true
# 开启ACK
spring.rabbitmq.listener.direct.acknowledge-mode=manual
spring.rabbitmq.listener.simple.acknowledge-mode=manual
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author zhengqiang.shi
* @Date 2019-03-19 16:15
*/
@Configuration
public class RabbitConfig implements InitializingBean {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* @Description: 配置MessageConverter,会自动设置到RabbitTemplate
* @see org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration
* @Param: []
* @return: org.springframework.amqp.support.converter.MessageConverter
*/
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
/**
* @Description: 配置消息发布确认、失败退回
* 需要在application.properties中显式开启
* spring.rabbitmq.publisher-confirms=true
* spring.rabbitmq.publisher-returns=true
* @Param: []
* @return: void
*/
@Override
public void afterPropertiesSet() throws Exception {
rabbitTemplate.setReturnCallback((message, replyCode, replyText,exchange,routingKey) -> {
logger.error("message:{}, replyCode:{} replyText:{} exchange: {} routingKey: {}", message, replyCode, replyText, exchange, routingKey);
});
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if(ack){
logger.info("发送成功");
} else {
logger.error("发送失败,msg:{}",cause);
}
});
}
}
注:消息传输需要序列化,默认实现为SimpleMessageConverter,此处配置为Jackson2JsonMessageConverter,原因为SimpleMessageConverter 对于要发送的消息体 body 为 byte[] 时不进行处理,如果是 String 则转成字节数组,如果是 Java 对象,则使用 jdk 序列化将消息转成字节数组,转出来的结果较大,含class类名,类相应方法等信息。因此性能较差。
package com.learn.fanout;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author zhengqiang.shi
* @Date 2019-03-19 17:45
*/
@Configuration
public class FanoutRabbitConfig {
/**
* @Description: 定义队列A
* @Param: []
* @return: org.springframework.amqp.core.Queue
*/
@Bean
public Queue queueA(){
return new Queue(FanoutConstant.QUEUE_NAME_A);
}
/**
* @Description: 定义队列B
* @Param: []
* @return: org.springframework.amqp.core.Queue
*/
@Bean
public Queue queueB(){
return new Queue(FanoutConstant.QUEUE_NAME_B);
}
/**
* @Description: 定义fanout类型的交换器
* @Param: []
* @return: org.springframework.amqp.core.FanoutExchange
*/
@Bean
public FanoutExchange fanoutExchange(){
return new FanoutExchange(FanoutConstant.EXCHANGE_NAME);
}
/**
* @Description: 绑定队列A
* @Param: [queueA, fanoutExchange]
* @return: org.springframework.amqp.core.Binding
*/
@Bean
public Binding bindingQueueA(Queue queueA,FanoutExchange fanoutExchange){
return BindingBuilder.bind(queueA).to(fanoutExchange);
}
/**
* @Description: 绑定队列B
* @Param: [queueB, fanoutExchange]
* @return: org.springframework.amqp.core.Binding
*/
@Bean
public Binding bindingQueueB(Queue queueB,FanoutExchange fanoutExchange){
return BindingBuilder.bind(queueB).to(fanoutExchange);
}
}
package com.learn.fanout;
/**
* @Author zhengqiang.shi
* @Date 2019-03-19 17:50
*/
public class FanoutConstant {
public static final String EXCHANGE_NAME = "com.msg.fanout";
public static final String QUEUE_NAME_A = "queue.A";
public static final String QUEUE_NAME_B = "queue.B";
}
package com.learn.fanout;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* @Author zhengqiang.shi
* @Date 2019-03-19 17:56
*/
@Component
public class FanoutReceiver {
@RabbitListener(queues = FanoutConstant.QUEUE_NAME_A)
public void receiveQueueA(String msg, Channel channel, Message message){
System.out.println("queueA receive:"+msg);
try {
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
} catch (IOException e) {
e.printStackTrace();
}
}
@RabbitListener(queues = FanoutConstant.QUEUE_NAME_B)
public void receiveQueueB(String msg,Channel channel, Message message){
System.out.println("queueB receive:"+msg);
try {
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
} catch (IOException e) {
e.printStackTrace();
}
}
}
import com.learn.DemoApplication;
import com.learn.fanout.FanoutConstant;
import com.learn.model.User;
import com.learn.topic.TopicConstant;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.time.LocalDateTime;
import java.util.Date;
/**
* @Author zhengqiang.shi
* @Date 2019-03-19 17:57
*/
@SpringBootTest(classes = DemoApplication.class)
@RunWith(SpringRunner.class)
public class TestRabbitMQ {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void sendByFanout() {
String msg = "hello " + LocalDateTime.now();
// fanout类型的交换器,会把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中,所以不用指定routingKey
rabbitTemplate.convertAndSend(FanoutConstant.EXCHANGE_NAME, "", msg);
}
}
queueA receive:hello 2019-03-19T18:08:17.598
queueB receive:hello 2019-03-19T18:08:17.598
# 其他类型direct、topic主要匹配routingKey,写法大同小异,此处不再举例