本篇实现topic方式。topic是在direct的基础上,强化路由模糊匹配,在topic交换机发布消息时带上路由key,绑定的队列路由key与消息发布的路由key模糊匹配上时会接收到消息。
配置交换机、队列及绑定关系可以在消费端,这里实现一种在消费端注册队列和绑定的写法。
生产端
- 交换机
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
/**
* @Description TODO
* @Author chanyu
* @Date 2022/5/27 16:57
* @Version 1.0
**/
@Configuration
public class TopicRabbitConfiguration {
@Bean
public TopicExchange topicExchange(){
return new TopicExchange("topic.order.exchange",true,false);
}
}
- 业务模拟生产消息
import java.util.UUID;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @Description TODO
* @Author chanyu
* @Date 2022/5/27 16:52
* @Version 1.0
**/
@Slf4j
@Service
public class OrderService {
@Autowired
private RabbitTemplate rabbitTemplate;
public void orderTopic(String userId , String goodsId , int num , String unit){
// 订单写入
String orderId = UUID.randomUUID().toString();
String msg = "创建订单"+orderId+",用户"+userId+"购买"+num+unit+"商品"+"goodsId";
log.info("创建订单{},用户{}购买{}{}商品{}",orderId,userId,num,unit,goodsId);
// 扣减库存
String exchangeName = "topic.order.exchange";
String routingKey = "com.sms.email.xxx";
// 可发给 #.sms.# #.email.#
// 发布消息
rabbitTemplate.convertAndSend(exchangeName,routingKey,msg);
}
}
消费端
- 消费消息
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Service;
/**
* @Description TODO
* @Author chanyu
* @Date 2022/5/27 17:34
* @Version 1.0
**/
@Slf4j
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = "email.topic.queue",durable = "true",autoDelete = "false"),
exchange = @Exchange(value = "topic.order.exchange",type = ExchangeTypes.TOPIC),
key = "#.email.#"
))
@Service
public class TopicEmailConsumerService {
@RabbitHandler
public void handlerMsg(String msg){
log.info(msg);
}
}
/**
* @Description TODO
* @Author chanyu
* @Date 2022/5/27 17:34
* @Version 1.0
**/
@Slf4j
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = "sms.topic.queue",durable = "true",autoDelete = "false"),
exchange = @Exchange(value = "topic.order.exchange",type = ExchangeTypes.TOPIC),
key = "#.sms.#"
))
@Service
public class TopicSmsConsumerService {
@RabbitHandler
public void handlerMsg(String msg){
log.info(msg);
}
}
验证
发布消息的路由key是com.sms.email.xxx,那么 key = “#.sms.#”, key = "#.email.#"的队列都能接收到。
import com.cy.rabbitmqproducer.service.OrderService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.concurrent.TimeUnit;
@SpringBootTest
class RabbitmqProducerApplicationTests {
@Autowired
private OrderService orderService;
@Test
void orderTopic() throws InterruptedException {
orderService.orderTopic("1","1",3,"件");
TimeUnit.SECONDS.sleep(1);
orderService.orderTopic("1","2",1,"个");
TimeUnit.SECONDS.sleep(1);
orderService.orderTopic("1","3",2,"条");
TimeUnit.SECONDS.sleep(1);
orderService.orderTopic("1","4",1,"件");
TimeUnit.SECONDS.sleep(1);
}
}
执行orderTopic(),创建了4条订单。
- 消费
运行消费端工程,sms和email都消费了消息。(注意先启动消费端工程,然后再执行生产端产生订单)
总结
topic模式关键在于路由key模糊匹配,交换机发送消息带上路由key,只有绑定交换机的队列并且路由key能模糊匹配上的能接收到该消息。
#.代表0-n级 n>=0,*.代表1-m级 m>0。