首先请确保你的rabbitmq服务已经打开,或者百度搜索安装
Exchange 类型
Exchange分发消息时根据类型的不同分发策略有区别,目前共四种类型:direct、fanout、topic、headers 。只说前三种模式。
1.Direct模式
消息中的路由键(routing key)如果和 Binding 中的 binding key 一致, 交换器就将消息发到对应的队列中。路由键与队列名完全匹配
2.Topic模式
topic 交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上。它将路由键和绑定键的字符串切分成单词,这些单词之间用点隔开。它同样也会识别两个通配符:符号“#”和符号“*”。#匹配0个或多个单词,*匹配一个单词。
3.Fanout模式
每个发到 fanout 类型交换器的消息都会分到所有绑定的队列上去。fanout 交换器不处理路由键,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。fanout 类型转发消息是最快的。
项目结构
pom
4.0.0
com.pwl
springboot-rabbitmq
0.0.1-SNAPSHOT
jar
springboot-rabbitmq
Demo project for Spring Boot
org.springframework.boot
spring-boot-starter-parent
2.0.4.RELEASE
UTF-8
UTF-8
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-amqp
org.springframework.boot
spring-boot-maven-plugin
application.properties
spring.application.name=spirng-boot-rabbitmq
#IP地址
spring.rabbitmq.host=127.0.0.1
#rabbitmq默认端口号
spring.rabbitmq.port=5672
#账户名和密码
spring.rabbitmq.username=pwl
spring.rabbitmq.password=pwl
首先创建一个实体User.java,需要实现Serializable 序列化接口
package com.pwl.springbootrabbitmq.entity;
import java.io.Serializable;
public class User implements Serializable {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
rabbitmq配置类RabbitConfig.java
package com.pwl.springbootrabbitmq.config;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitConfig {
//topic
public static final String TOPIC_QUEUE1 = "topic.queue1";
public static final String TOPIC_QUEUE2 = "topic.queue2";
public static final String TOPIC_EXCHANGE = "topic.exchange";
//fanout
public static final String FANOUT_QUEUE1 = "fanout.queue1";
public static final String FANOUT_QUEUE2 = "fanout.queue2";
public static final String FANOUT_EXCHANGE = "fanout.exchange";
//redirect模式
public static final String DIRECT_QUEUE1 = "direct.queue1";
public static final String DIRECT_EXCHANGE = "direct.exchange";
public static final String DIRECT_QUEUE2 ="direct.queue2" ;
/**
* Topic模式
*
* @return
*/
@Bean
public Queue topicQueue1() {
return new Queue(TOPIC_QUEUE1);
}
@Bean
public Queue topicQueue2() {
return new Queue(TOPIC_QUEUE2);
}
@Bean
public TopicExchange topicExchange() {
return new TopicExchange(TOPIC_EXCHANGE);
}
@Bean
public Binding topicBinding1() {
return BindingBuilder.bind(topicQueue1()).to(topicExchange()).with("lzc.message");
}
@Bean
public Binding topicBinding2() {
return BindingBuilder.bind(topicQueue2()).to(topicExchange()).with("lzc.#");
}
/**
* Fanout模式
* Fanout 就是我们熟悉的广播模式或者订阅模式,给Fanout交换机发送消息,绑定了这个交换机的所有队列都收到这个消息。
* @return
*/
@Bean
public Queue fanoutQueue1() {
return new Queue(FANOUT_QUEUE1);
}
@Bean
public Queue fanoutQueue2() {
return new Queue(FANOUT_QUEUE2);
}
@Bean
public FanoutExchange fanoutExchange() {
return new FanoutExchange(FANOUT_EXCHANGE);
}
@Bean
public Binding fanoutBinding1() {
return BindingBuilder.bind(fanoutQueue1()).to(fanoutExchange());
}
@Bean
public Binding fanoutBinding2() {
return BindingBuilder.bind(fanoutQueue2()).to(fanoutExchange());
}
/**
* direct模式
* 消息中的路由键(routing key)如果和 Binding 中的 binding key 一致, 交换器就将消息发到对应的队列中。路由键与队列名完全匹配
* @return
*/
@Bean
public Queue directQueue1() {
return new Queue(DIRECT_QUEUE1);
}
@Bean
public DirectExchange directExchange() {
return new DirectExchange(DIRECT_EXCHANGE);
}
@Bean
public Binding directBinding1() {
return BindingBuilder.bind(directQueue1()).to(directExchange()).with("direct.pwl");
}
}
Fanout模式
消息发送类FanoutSender.java
package com.pwl.springbootrabbitmq.sender;
import com.pwl.springbootrabbitmq.config.RabbitConfig;
import com.pwl.springbootrabbitmq.entity.User;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class FanoutSender {
@Autowired
private AmqpTemplate rabbitTemplate;
public void send(User user) {
this.rabbitTemplate.convertAndSend(RabbitConfig.FANOUT_EXCHANGE, "", user);
}
}
消息接收类:
package com.pwl.springbootrabbitmq.Receiver;
import com.pwl.springbootrabbitmq.config.RabbitConfig;
import com.pwl.springbootrabbitmq.entity.User;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class FanoutReceiver {
// queues是指要监听的队列的名字
@RabbitListener(queues = RabbitConfig.FANOUT_QUEUE1)
public void receiveTopic1(User user) {
System.out.println("【receiveFanout1监听到消息】" + user);
}
@RabbitListener(queues = RabbitConfig.FANOUT_QUEUE2)
public void receiveTopic2(User user) {
System.out.println("【receiveFanout2监听到消息】" + user);
}
}
测试类
package com.pwl.springbootrabbitmq;
import com.pwl.springbootrabbitmq.entity.User;
import com.pwl.springbootrabbitmq.sender.DirectSender;
import com.pwl.springbootrabbitmq.sender.FanoutSender;
import com.pwl.springbootrabbitmq.sender.TopicSender;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootRabbitmqApplicationTests {
@Autowired
private FanoutSender fanoutSender;
@Autowired
private TopicSender topicSender;
@Autowired
private DirectSender directSender;
/**
* Fanout测试
* @throws Exception
*/
@Test
public void testFanout() throws Exception {
User user=new User();
user.setId("1");
user.setName("pwl");
fanoutSender.send(user);
}
/**
* TOPIC测试
* @throws Exception
*/
@Test
public void testTopic() throws Exception {
User user=new User();
user.setId("1");
user.setName("pwl");
topicSender.send(user);
}
/**
* DIRECT测试
* @throws Exception
*/
@Test
public void testDirect() throws Exception {
User user=new User();
user.setId("1");
user.setName("pwl");
directSender.send(user);
}
}
fanout类型的Exchange路由规则非常简单,它会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中。
结果:
Direct模式:
DirectSender.java
package com.pwl.springbootrabbitmq.sender;
import com.pwl.springbootrabbitmq.config.RabbitConfig;
import com.pwl.springbootrabbitmq.entity.User;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class DirectSender {
@Autowired
private RabbitTemplate rabbitTemplate;
public void send(User user) {
this.rabbitTemplate.convertAndSend(RabbitConfig.DIRECT_EXCHANGE, "direct.pwl", user);
}
}
接收类
package com.pwl.springbootrabbitmq.Receiver;
import com.pwl.springbootrabbitmq.config.RabbitConfig;
import com.pwl.springbootrabbitmq.entity.User;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class DirectReceiver {
// queues是指要监听的队列的名字
@RabbitListener(queues = RabbitConfig.DIRECT_QUEUE1)
public void receiveDirect1(User user) {
System.out.println("【receiveDirect1监听到消息】" + user);
}
@RabbitListener(queues = RabbitConfig.DIRECT_QUEUE1)
public void receiveDirect2(User user) {
System.out.println("【receiveDirect2监听到消息】" + user);
}
}
测试
direct (重定向)
direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routing key完全匹配的Queue中。
以上图的配置为例,我们以routingKey=”error”发送消息到Exchange,则消息会路由到Queue1(amqp.gen-S9b…,这是由RabbitMQ自动
生成的Queue名称)和Queue2(amqp.gen-Agl…);如果我们以routingKey=”info”或routingKey=”warning”来发送消息,则消息只会路由
到Queue2。如果我们以其他routingKey发送消息,则消息不会路由到这两个Queue中。
TOPIC模式
sender
package com.pwl.springbootrabbitmq.sender;
import com.pwl.springbootrabbitmq.config.RabbitConfig;
import com.pwl.springbootrabbitmq.entity.User;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class TopicSender {
@Autowired
private AmqpTemplate rabbitTemplate;
// 第一个参数:TopicExchange名字
// 第二个参数:Route-Key
// 第三个参数:要发送的内容
public void send(User user) {
this.rabbitTemplate.convertAndSend(RabbitConfig.TOPIC_EXCHANGE,"lzc.message", user);
this.rabbitTemplate.convertAndSend(RabbitConfig.TOPIC_EXCHANGE, "lzc.lzc", user);
}
}
接收
package com.pwl.springbootrabbitmq.Receiver;
import com.pwl.springbootrabbitmq.config.RabbitConfig;
import com.pwl.springbootrabbitmq.entity.User;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class TopicReceiver {
// queues是指要监听的队列的名字
@RabbitListener(queues = RabbitConfig.TOPIC_QUEUE1)
public void receiveTopic1(User user) {
System.out.println("【receiveTopic1监听到消息】" + user.toString());
}
@RabbitListener(queues = RabbitConfig.TOPIC_QUEUE2)
public void receiveTopic2(User user) {
System.out.println("【receiveTopic2监听到消息】" + user.toString());
}
}
测试:
topic(主题)
前面讲到direct类型的Exchange路由规则是完全匹配binding key与routing key,但这种严格的匹配方式在很多情况下不能满足实际业务需求。topic类型的Exchange在匹配规则上进行了扩展,它与direct类型的Exchage相似,也是将消息路由到binding key与routing key相匹配的Queue中,但这里的匹配规则有些不同,它约定:
以上图中的配置为例,routingKey=”quick.orange.rabbit”的消息会同时路由到Q1与Q2,routingKey=”lazy.orange.fox”的消息会路由到Q1,
routingKey=”lazy.brown.fox”的消息会路由到Q2,routingKey=”lazy.pink.rabbit”的消息会路由到Q2(只会投递给Q2一次,虽然这个routingKey与Q2的两个bindingKey都匹配);
routingKey=”quick.brown.fox”、routingKey=”orange”、routingKey=”quick.orange.male.rabbit”的消息将会被丢弃,因为它们没有匹配任何bindingKey。
项目地址:https://github.com/James-Pan0525/springboot