RabbitMQ
RabbitMQ由erlang语言开发的遵从AMQP(Advanved Message Queue)的开源实现。
组成
发送者,队列,接受者,在发送者和队列之间存在着交换机。
交换机
交换机决定着消息的走向,主要的功能用于接受消息并将消息发送到绑定的队列,不存储消息,若没有队列接受,则会抛弃消息。交换机有路由键
交换机有4种种类:Direct,Topic,Headers,Fanout
Direct Exchange:为交换机默认模式。处理路由键。需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配。这是一个完整的匹配。
Topic Exchange:将路由键和某模式进行匹配。此时队列需要绑定要一个模式上。符号“#”匹配一个或多个词,符号“*”匹配不多不少一个词。
Headers Exchange:路由器和交换机路由的规则是通过Headers
信息来交换的,消息发送的时候,会携带一组hash数据结构的信息,当Hash
的内容匹配上的时候,消息就会被写入队列。
Fanout Exchange:不处理路由键。你只需要简单的将队列绑定到交换机上。一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。
集成RabbitMQ
一:添加依赖
<!--RabbitMQ依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
二:配置
spring:
rabbitmq:
//默认端口
port: 5672
//本地主机
host: 127.0.0.1
//默认
username: guest
password: guest
二:简单的Hello,wordle形式,分别编写队列,发送者,接受者,测试
队列:
@Configuration
public class queue1 {
@Bean
public Queue show() {
return new Queue("hell");
}
}
发送者:
@Component
public class sender1 {
@Autowired
private AmqpTemplate rabbitTempalte;
public void send() {
String context = "这是一个发送消息的队列!!";
System.out.println("sender: "+context);
rabbitTempalte.convertAndSend("hello", context);
}
}
接受者:
@Component
@RabbitListener(queues="hello")
public class HelloRaceiver {
@RabbitHandler
public void show(String hello) {
System.out.println("receiver: "+hello);
}
}
测试类:
@RestController
public class RabbitController {
@Autowired
private sender1 sender1;
@GetMapping("/rabbit")
public String show() {
sender1.send();
return "成功";
}
}
各种情况
一对N的情况会怎样:一个发送者,N个队列
试验结果:消息会均匀分布到队列中去。
多对多又会怎样:N个发送者,N个接受者
试验结果:与一对一相同,消息仍然会均匀分布到队列中。
能否发送对象?答案:of cource 必须的,前提为对象实现序列化接口
Topic Exchange
我们要实现:发送消息1,消息2,消息1两个队列都可以接受,消息2只能队列2能接受。
这就需要用到Topic Exchange
队列:
@Configuration
public class queue {
@Bean
public Queue message1() {
return new Queue("topic.message1");
}
@Bean
public Queue message2() {
return new Queue("topic.message2");
}
//声明交换机
@Bean
TopicExchange exchange() {
return new TopicExchange("topic");
}
//这里就好像在和交换机说我能接受什么标记的消息
@Bean
Binding bindingexchangemessage1(Queue message1, TopicExchange topic) {
return BindingBuilder.bind(message1).to(topic).with("topic.message1");
}
@Bean
Binding bindingexchangemessage2(Queue message2, TopicExchange topic) {
return BindingBuilder.bind(message2).to(topic).with("topic.#");
}
}
发送者:
public void send2() {
String context = "这是一个发送消息的队列!!";
System.out.println("sender3: " + context);
rabbitTempalte.convertAndSend("topic","topic.message1", context);
}
public void send3() {
String context = "这是一个发送消息的队列!!";
System.out.println("sender4: " + context);
rabbitTempalte.convertAndSend("topic","topic.message2", context);
}
执行send2,两个队列都可以接收到消息。
执行send3,只有第二个队列猜可以接受到消息
Fanout Exchange
绑定到该交换机的任何队列都会接受到消息。
@Configuration
public class queue3 {
@Bean
public Queue message1() {
return new Queue("message1");
}
@Bean
public Queue message2() {
return new Queue("message2");
}
@Bean
FanoutExchange exchange() {
return new FanoutExchange("Fanout");
}
@Bean
Binding bindingexchangemessage1(Queue message1, FanoutExchange Fanout) {
return BindingBuilder.bind(message1).to(Fanout);
}
@Bean
Binding bindingexchangemessage2(Queue message2, FanoutExchange Fanout) {
return BindingBuilder.bind(message2).to(Fanout);
}
}
public void send4() {
String context = "这是一个广播的消息";
System.out.println("sender5: " + context);
rabbitTempalte.convertAndSend("Fanout","",context);
}
routingKey写什么都行,到最后都会被忽略。