目录
官方网站:RabbitMQ
介绍
具体来说,Direct Exchange 是一种按照精确匹配方式进行路由的 Exchange,即只有 Routing Key 与 Binding Key 完全匹配的消息才会被路由到指定的 Queue 中。这种精确匹配方式使得应用程序可以非常精细地控制每条消息的处理流程,同时也能够很好地控制消息的负载均衡和可靠性。
使用 「Bean」配置 Direct 交换机
/**
* 直接交换机Bean配置
*
* @author xiangtianlei
* @date 2023/06/07
*/
@Configuration
public class DirectExchangeConfig {
@Bean(name = "directQueueOne")
public Queue directQueueOne() {
return new Queue("direct_queue_one", true, false, false);
}
@Bean(name = "directQueueTwo")
public Queue directQueueTwo() {
return new Queue("direct_queue_two", true, false, false);
}
@Bean(name = "directExchange")
public Exchange directExchange() {
return new DirectExchange("direct_exchange");
}
@Bean(name = "directBindingOne")
public Binding directBindingOne(@Qualifier("directQueueOne") Queue queue, Exchange directExchange) {
return BindingBuilder.bind(queue).to(directExchange).with("one").noargs();
}
@Bean(name = "directBindingTwo")
public Binding directBindingTwo(@Qualifier("directQueueTwo") Queue queue, Exchange directExchange) {
return BindingBuilder.bind(queue).to(directExchange).with("two").noargs();
}
}
@Bean(name = "directQueueOne")
是一种声明 Bean 的注解配置,它会在 Spring 容器中创建一个名为"directQueueOne"
的 Bean 实例,并返回这个 Bean 实例的引用。通过这个注解,我们就可以将队列定义为一个 Spring Bean,并在需要的地方进行注入,使得它可以被其他组件所使用。
@Qualifier
注解是 Spring 框架中用于指定依赖注入的具体实现类对象的注解。在使用 Spring IoC 容器进行依赖注入时,如果存在多个同类型的实例对象,就需要通过@Qualifier
注解来标识要注入的实例对象。例如,假设我们有一个接口
PersonService
,它有两个实现类:StudentServiceImpl
和TeacherServiceImpl
。如果我们在代码中需要注入PersonService
类型的对象,但不指定具体的实现类,Spring IoC 容器就会因为无法选择要注入哪个实现类而报错。
使用 「注解 」配置 Direct 交换机①
/**
* Direct交换机消费者配置
*
* @author xiangtianlei
* @date 2023/06/07
*/
@Component
public class ConsumerDirect {
Logger logger = LoggerFactory.getLogger(ConsumerDirect.class);
@RabbitListener(bindings = @QueueBinding(
value = @Queue("direct_queue_one"),
exchange = @Exchange(name = "direct_exchange", type = ExchangeTypes.DIRECT),
key = {"one", "two"}
))
public void readDirectQueueOne(String msg) {
logger.info("当前时间为:{},仅接收key为one和two的队列的消息,接收到的信息为:{}", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), msg);
}
@RabbitListener(bindings = @QueueBinding(
value = @Queue("direct_queue_two"),
exchange = @Exchange(name = "direct_exchange", type = ExchangeTypes.DIRECT),
key = {"two"}
))
public void readDirectQueueTwo(String msg) {
logger.info("当前时间为:{},仅接收key为two的队列的消息,接收到的信息为:{}", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), msg);
}
}
使用 「注解 」配置 Direct 交换机②
/**
* Direct交换机消费者配置
*
* @author xiangtianlei
* @date 2023/06/07
*/
@Component
@RabbitListener(bindings = @QueueBinding(
value = @Queue("direct_queue_one"),
exchange = @Exchange(name = "direct_exchange", type = ExchangeTypes.DIRECT),
key = {"one", "two", "three"}
))
public class ConsumerDirect {
Logger logger = LoggerFactory.getLogger(ConsumerDirect.class);
@RabbitHandler
public void processMessage(String message) {
logger.info("当前时间为:{},仅接收key为one和two的队列的消息,入参类型为字符串格式,接收到的信息为:{}", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), message);
}
@RabbitHandler
public void processMessage(@Payload User user) {
logger.info("当前时间为:{},仅接收key为one和two的队列的消息,入参类型为User对象,接收到的信息为:{}", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), user);
}
@RabbitHandler
public void processMessage(byte[] bytes) {
logger.info("当前时间为:{},仅接收key为one和two的队列的消息,入参类型为byte,接收到的信息为:{}", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), new String(bytes));
}
@RabbitHandler
public void processMessage(Map<String, Object> map) {
logger.info("当前时间为:{},仅接收key为one和two的队列的消息,入参类型为map类型,接收到的信息为:{}", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), map);
}
}
模拟生产者发送消息①
@SpringBootTest(classes = MqApplication.class)
@RunWith(SpringRunner.class)
public class ProducerDirectTest {
@Resource
RabbitTemplate rabbitTemplate;
@Test
public void sendDelayMessageByDirect() {
rabbitTemplate.convertAndSend(
"direct_exchange",
"two",
"发送消息到路由键为two的队列中"
);
rabbitTemplate.convertAndSend(
"direct_exchange",
"one",
"发送消息到路由键为one的队列中"
);
}
}
这段代码是使用 RabbitMQ 的
RabbitTemplate
对象来发送消息到指定的交换机和队列中。具体来说,代码中调用了两次convertAndSend()
方法,分别向名为direct_exchange
的直连交换机发送消息,消息内容分别为"发送消息到路由键为two的队列中"
和"发送消息到路由键为one的队列中"
,同时指定了不同的路由键。根据 RabbitMQ 的消息路由机制,这两条消息会被发送到不同的队列中,其中一条会进入名为one
的队列,另一条则会进入名为two
的队列。具体来说,RabbitMQ 中的交换机(Exchange)通常用于接收生产者发送的消息,根据指定的路由键和绑定关系,将消息路由到一个或多个队列中。在本例中,使用了名为
direct_exchange
的直连交换机,它与名为one
和two
的两个队列分别绑定,绑定关系使用路由键进行匹配。当生产者发送消息到交换机时,消息会根据指定的路由键被路由到绑定了该路由键的队列中。需要注意的是,如果交换机没有任何队列与其绑定,或者路由键与所有队列都没有绑定关系,那么消息将会被丢弃。因此,在使用 RabbitMQ 进行消息传递时,交换机和队列的绑定关系非常重要,需要仔细设计和管理。
模拟生产者发送消息②
@SpringBootTest(classes = MqApplication.class)
@RunWith(SpringRunner.class)
public class ProducerDirectTest {
@Resource
RabbitTemplate rabbitTemplate;
@Test
public void sendDelayMessageByDirect() {
rabbitTemplate.convertAndSend(
"direct_exchange",
"two",
new User(24, "张三", "男")
);
rabbitTemplate.convertAndSend(
"direct_exchange",
"three",
"发送消息到路由键为two的队列中"
);
Map<String, Object> map = new HashMap<>();
map.put("name", "向天磊");
rabbitTemplate.convertAndSend(
"direct_exchange",
"three",
map
);
rabbitTemplate.convertAndSend(
"direct_exchange",
"three",
"你好bety".getBytes()
);
}
}
此测试方法发送了不同的消息类型,在消费端根据不同的类型调用不同的方法
注:一个方法中同时发送多个convertAndSend,只有第一个convertAndSend生效
启动成功之后,在RabbitMq控制面板即可看见已经自动创建好交换机和队列,并且交换机和队列已经绑定在了一起,如图1-1,1-2,1-3所示
图1-1 消费队列
图1-2 直连交换机
图1-3 交换机和队列绑定图