/**
* 五种工作模式
* 1.Basic Queue 简单模式
* 一个生产者一个消费者 不需要设置交换机 使用默认得交换机
*
* 一个消费消费者得时候 代码提现得是一个 @RabbitListener
*
* 2.Work queues 工作队列模式
* 一个生产 多个消费者者 竞争关系 一个消费者消费成功了就 没了
* 多个消费这时候 竞争关系
* 3.Pub/Sub 订阅模式
*
* 需要设置类型为fanout 得交换机 并且交换机和对列要进行绑定 再发送到交换机后 交换机会将消息 发送到绑定得队列
*
* 4.Routing 路由模式
*
* 需要设置类型为direct得交换及并且交换机和队列绑定 指定 routing key 当消息发送到交换机后 交换机会根据 routingkey 将消息发送到对应得队列
*
* 5.Topics 通配符模式
*
* 需要设置类型为topic得交换机 交换机和队列绑定 指定通配符方式得 routing key 当消息发送到交换机后 交换机会根据 routingkey 将消息发送到对应得队列
*
*
*/
整合maven:
org.springframework.boot
spring-boot-starter-amqp
2.5.5
yml 配置:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
#开启发送到交换机确认callback
#NONE值是禁用发布确认模式,是默认值
#CORRELATED值是发布消息成功到交换器后会触发回调方法,如1示例
#SIMPLE值经测试有两种效果,
#其一效果和CORRELATED值一样会触发回调方法,#
#其二在发布消息成功后使用rabbitTemplate调用waitForConfirms或waitForConfirmsOrDie方法等待broker节点返回发送结果,根据返回结果来判定下一步的逻辑,要注意的点是waitForConfirmsOrDie方法如果返回false则会关闭channel,则接下来无法发送消息到broker;
publisher-confirm-type: correlated
#开启发送到队列失败returnCallback
publisher-returns: true
#消息是否强制回退 如果此值为空才取publisher-returns值
template:
mandatory: true
#开启手动确认
listener:
direct:
acknowledge-mode: manual
simple:
acknowledge-mode: manual
初始化Exchange 和Queue:
/**
* rabbitMq 初始化
*
* @author chenkang
* @date 2022/5/12 17:56
*/
@Component
public class RabbitIniter {
@Resource
private AmqpAdmin amqpAdmin;
@Resource
private RabbitTemplate rabbitTemplate;
@Resource
private RabbitMqConfirmService rabbitMqConfirmService;
@Bean
public void initRabbitConfig(){
rabbitTemplate.setConfirmCallback(rabbitMqConfirmService);
rabbitTemplate.setReturnsCallback(rabbitMqConfirmService);
}
/**
* 声明一个普通队列
*/
@Bean
public void common() {
amqpAdmin.declareQueue( new Queue("station_common"));
}
/**
* 声明一个Fanout 并绑定 只要绑定
*/
@Bean
public void fanOut() {
Queue stationFanOut = new Queue("station_fanOut");
FanoutExchange fanoutExchange = new FanoutExchange("exchanges.fanout");
amqpAdmin.declareQueue(stationFanOut);
amqpAdmin.declareExchange(fanoutExchange);
amqpAdmin.declareBinding(new Binding(
stationFanOut.getName(),
Binding.DestinationType.QUEUE,
fanoutExchange.getName(),
"",
new HashMap<>(2)
));
}
/**
* 声明一个Route 并绑定需要 routeKey
*/
@Bean
public void route() {
Queue stationRoute = new Queue("station_Route");
DirectExchange directExchange = new DirectExchange("exchanges.route");
amqpAdmin.declareQueue(stationRoute);
amqpAdmin.declareExchange(directExchange);
amqpAdmin.declareBinding(new Binding(
stationRoute.getName(),
Binding.DestinationType.QUEUE,
directExchange.getName(),
"route_exchange",
new HashMap<>(4)
));
}
/**
* 声明一个Route 并绑定
*/
@Bean
public void topic() {
Queue stationTopic = new Queue("station_topic");
TopicExchange topicExchange = new TopicExchange("exchanges.topic");
amqpAdmin.declareQueue(stationTopic);
amqpAdmin.declareExchange(topicExchange);
amqpAdmin.declareBinding(new Binding(
stationTopic.getName(),
Binding.DestinationType.QUEUE,
topicExchange.getName(),
"*.log",
new HashMap<>(6)
));
}
定义确认类实现
/**
* @author chenkang
* @date 2022/5/13 10:56
*/
@Slf4j
@Component
public class RabbitMqConfirmService implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnsCallback {
/**
* 消息发送确认是否到 Exchange
* @param correlationData 消息id
* @param isAck
* @param s
*/
@Override
public void confirm(CorrelationData correlationData, boolean isAck, String s) {
if (isAck) {
log.info("消息已发送到交换器 cause:{} - {}" , s , correlationData.toString());
} else {
log.info("消息未发送到交换器 cause:{} - {}" , s , correlationData.toString());
}
}
/**
* exchange没有发送到队列的callback
*/
@Override
public void returnedMessage(ReturnedMessage returnedMessage) {
log.info("消息被退回 {}" , returnedMessage.toString());
}
}
编写控制器:
/**
* @author chenkang
* @date 2022/5/10 17:45
*/
@RestController
@RequestMapping("rabbit")
public class RabbitMqController {
@Resource
private RabbitTemplate rabbitTemplate;
/**
* 普通模式
*/
@GetMapping("common")
public void sendMessage(){
rabbitTemplate.convertAndSend("station_test","{name:123}");
}
/**
* 发布和订阅模式
*/
@GetMapping("pub")
public void pubsendMessage(){
//消息确认时候 new CorrelationData()
rabbitTemplate.convertAndSend("amq.fanout","station_test","{name:123}",new CorrelationData());
}
/**
* direct
*/
@GetMapping("direct")
public void directsendMessage(){
rabbitTemplate.convertAndSend("amq.direct","direct_route","{name:123}", new CorrelationData());
}
/**
* topic 模式
*/
@GetMapping("topic")
public void topicsendMessage(){
rabbitTemplate.convertAndSend("amq_topic","error.log","{name:123}");
}
}
消息接收和确认
/**
* @author chenkang
* @date 2022/5/11 14:14
*/
@Component
public class RabbtMqMessageReceiver {
/**
* 消息手动回复
* @param msg 消息内容
* @param message playload
* @param channel channel
* @throws InterruptedException
*/
@RabbitListener(queues = "station_test")
public void listenSimpleQueueMessage(String msg, Message message, Channel channel) throws InterruptedException, IOException {
System.out.println(message);
System.out.println("spring 消费者1接收到消息:【" + msg + "】");
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
}
/**
*
* channel.basicAck(msg.getMessageProperties().getDeliveryTag(),false);
* ack表示确认消息。multiple:false只确认该delivery_tag的消息,true确认该delivery_tag的所有消息
*
* channel.basicReject(msg.getMessageProperties().getDeliveryTag(),false);
* Reject表示拒绝消息。requeue:false表示被拒绝的消息是丢弃;true表示重回队列
*
* channel.basicNack(msg.getMessageProperties().getDeliveryTag(),false,false);
* nack表示拒绝消息。multiple表示拒绝指定了delivery_tag的所有未确认的消息,requeue表示不是重回队列
*
*/
@RabbitListener(queues = "station_test")
public void listenSimpleQueueMessage2(String msg,Message message, Channel channel) throws InterruptedException, IOException {
System.out.println("spring 消费者2接收到消息:【" + msg + "】");
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
}
@RabbitListener(queues = "station_common")
public void listenSimpleQueueMessage3(String msg) throws InterruptedException {
System.out.println("spring 消费者2接收到消息:【" + msg + "】");
}
}
开启事务:
@Bean
public void initRabbitConfig(){
rabbitTemplate.setConfirmCallback(rabbitMqConfirmService);
rabbitTemplate.setReturnsCallback(rabbitMqConfirmService);
rabbitTemplate.setChannelTransacted(true);
}
@Bean("rabbitTransactionManager")
public RabbitTransactionManager rabbitTransactionManager(CachingConnectionFactory cachingConnectionFactory){
return new RabbitTransactionManager(cachingConnectionFactory);
}
开启事务就不能开启消息确认
#开启事务的时候这个就不能设置了
publisher-confirm-type: correlated
/**
* direct
*/
@GetMapping("direct")
@Transactional(rollbackFor = Exception.class,transactionManager = "rabbitTransactionManager")
public void directsendMessage(){
rabbitTemplate.convertAndSend("amq.direct","direct_route","{name:123}", new CorrelationData());
rabbitTemplate.convertAndSend("amq.direct","direct_route","{name:456}", new CorrelationData());
}