RabbitMq 基础二 交换机概论及直流交换机代码)
在很多文章当中我们会发现不同的角度来看点mq,有从交换机的角度,也有从队列角度来看,其实本质是一样的,后面文章我们先讲解交换机的角度后讲解队列角度。从代码的过程中去体会其差别。
交换机角度
RabbitMQ常用的交换器类型有direct、topic、fanout、headers四种。
Direct Exchange
该类型的交换器将所有发送到该交换器的消息被转发到RoutingKey指定的队列中,也就是说路由到BindingKey和RoutingKey完全匹配的队列中。
直连型交换机,根据消息携带的路由键将消息投递给对应队列。
大致流程,有一个队列绑定到一个直连交换机上,同时赋予一个路由键 routing key 。然后当一个消息携带着路由值为X,这个消息通过生产者发送给交换机时,交换机就会根据这个路由值X去寻找绑定值也是X的队列。
Topic Exchange
该类型的交换器将所有发送到Topic Exchange的消息被转发到所有RoutingKey中指定的Topic的队列上面。
Exchange将RoutingKey和某Topic进行模糊匹配,其中“”用来匹配一个词,“#”用于匹配一个或者多个词。例如“com.#”能匹配到“com.rabbitmq.oa”和“com.rabbitmq”;而"login."只能匹配到“com.rabbitmq”。
解释2:
主题交换机,这个交换机其实跟直连交换机流程差不多,但是它的特点就是在它的路由键和绑定键之间是有规则的。
简单地介绍下规则:
*(星号) 用来表示一个单词 (必须出现的)
#(井号) 用来表示任意数量(零个或多个)单词
通配的绑定键是跟队列进行绑定的,举个小例子
队列Q1 绑定键为 .TT. 队列Q2绑定键为 TT.#
如果一条消息携带的路由键为 A.TT.B,那么队列Q1将会收到;
如果一条消息携带的路由键为TT.AA.BB,那么队列Q2将会收到;
主题交换机是非常强大的,为啥这么膨胀?
当一个队列的绑定键为 “#”(井号) 的时候,这个队列将会无视消息的路由键,接收所有的消息。当 * (星号) 和 # (井号) 这两个特殊字符都未在绑定键中出现的时候,此时主题交换机就拥有的直连交换机的行为。所以主题交换机也就实现了扇形交换机的功能,和直连交换机的功能。
直流交换机代码:
前提要素1:yml配置文件
server:
port: 8111
servlet:
context-path: /hllhj-server
spring:
datasource:
url: jdbc:mysql://xxxx:3306/hllhj?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: xxxx
#这里面有个坑 访问地址是15672 实际Java这里端口号5672
rabbitmq:
host: xxxx
port: 5672
username: admin
password: xxxx
virtual-host: /
#消息确认配置项
#确认消息已发送到交换机(Exchange)
# publisher-confirms: true(老版本)
#确认消息已发送到队列(Queue)
publisher-returns: true
#新版本
publisher-confirm-type: CORRELATED
mybatis:
mapper-locations: classpath:mapper/*/*.xml,classpath*:mapper/*.xml
ftp:
ip: 192.168.137.1
username: zhangwen
password: 123456
port: 21
前提要素2 pom文件
<!--rabbitmq-->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-amqp -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
(1)直流交换机配置(生产者)
package com.zyw.rabbitmq.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author zyw
*/
@Configuration
public class DirectRabbitConfig {//直流交换机配置(生产者)
@Bean
public Queue TestDirectQueue() {//队列 起名:TestDirectQueue
// durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
// exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
// autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
// return new Queue("TestDirectQueue",true,true,false);
//一般设置一下队列的持久化就好,其余两个就是默认false
return new Queue("TestDirectQueue",true);
}
@Bean
DirectExchange TestDirectExchange() {//Direct交换机 起名:TestDirectExchange
// return new DirectExchange("TestDirectExchange",true,true);
return new DirectExchange("TestDirectExchange",true,false);
}
@Bean
Binding bindingDirect() {//绑定 将队列和交换机绑定, 并设置用于匹配键:TestDirectRouting
return BindingBuilder.bind(TestDirectQueue()).to(TestDirectExchange()).with("TestDirectRouting");
}
@Bean
DirectExchange lonelyDirectExchange() {
return new DirectExchange("lonelyDirectExchange");
}
}
(2)配置完以后 准备发送消息(生产者发送消息)
package com.zyw.rabbitmq.controller;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author zyw
*/
@RestController
@CrossOrigin("*")
@RequestMapping("/rq")
public class DemoController {
@Autowired
RabbitTemplate rabbitTemplate;
@RequestMapping("/shows")
public Object show(){ //直流交换机测试
System.out.println("444");
//将消息携带绑定键值:TestDirectRouting 发送到交换机TestDirectExchange
rabbitTemplate.convertAndSend("TestDirectExchange","TestDirectRouting","66666");
return "0";
}
}
(3) 消费者进行监听队列
package com.zyw.rabbitcustomer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @author zyw
* 监听的队列名称 TestDirectQueue
*/
@Component
@RabbitListener(queues = "TestDirectQueue")
public class DirectReceiver {
@RabbitHandler
public void process(String testMessage){
//String testMessage 这里传参的类型可以改变的 需要看生产者提供什么样的数据 我们应为生产者直接写死了666字符串类型传过来所有我们直接string类型接收,在真实环境中我们一般可以采用Map集合的形式进行接收
System.out.println("DirectReceiver消费者收到消息 : " + testMessage);
}
}
注意:如果我们在生产者的代码进行改造 变成一个定时任务去调用接口,那么消费者会在每一次定时任务执行的时候 接收到传递来的信息。
以上最简单的直流交换机的程序,当我们要查看是否推送成功,可以看服务器上的显示 如下:
消息已经推送到rabbitMq服务器上面了
当然消费者也可以生产者,如果想要成为生产者 需要配置和生产者一样的配置类 和yml文件中虚拟机的 填写 即可。