一、 Hello Wold 简单模式
1.一对一消费,只有一个消费者能接收到
a.生产者
@RestController
@RequestMapping("/rabbitmq")
public class HelloWorldController {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 第一种模型: 简单模型
* 一个消息生产者 一个队列 一个消费者
* @return
*/
@GetMapping("/hello/world")
public void helloWorld(){
// 发送消息
// 第一个参数: String routingKey 路由规则 【交换机 和队列的绑定规则 】 队列名称
// 第二个参数: object message 消息的内容
rabbitTemplate.convertAndSend("hello_world_queue","hello world rabbit!");
}
b.消费者
@Component
@Log4j2
public class HelloWorldConsumer {
/**
* 监听 hello_world_queue 队列消费消息
* queues 监听队列的名称 要求这个队列必须是已经存在的队列
* queuesToDeclare 监听队列 如果这个队列不存在 则 rabbitMQ 中 RabbitAdmin 会帮助去构建这个队列
*/
@RabbitListener(queuesToDeclare = @Queue(name = "hello_world_queue"))
public void helloWorldConsumer(String message){
log.info("hello_world_queue队列消费者接收到了消息,消息内容:{}", message);
}
}
二、 Work queues 工作队列模式
1.多个消费者,你一个我一个分配消费消息,有预取机制,默认公平消费,可配置能者多 劳模式,谁完成的快,谁多做一点
a.配置文件(bootStrap.yml记得host改成自己云服务器的ip)
取消预取机制,能者多劳配置
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtual-host: /
listener:
simple:
prefetch: 1 # 每次只能获取一条,处理完成才能获取下一条
b.生产者
/**
* 工作队列
* 一个生产者 一个队列 多个消费者
*/
@GetMapping("work/queue")
public void workQueue() {
for (int i = 1; i <= 10; i++) {
rabbitTemplate.convertAndSend("work_queue", i + "hello work queue!");
}
}
c.消费者
@Component
@Log4j2
public class WorkQueueConsumer {
/***
* 消费者1
* @param message
*/
@RabbitListener(queuesToDeclare = @Queue("work_queue"))
public void workQueueConsumer(String message) throws InterruptedException {
Thread.sleep(200);
log.info("work_queue队列消费者1接收到了消息,消息内容:{}", message);
}
/***
* 消费者2
* @param message
*/
@RabbitListener(queuesToDeclare = @Queue("work_queue"))
public void workQueueConsumer2(String message) throws InterruptedException {
Thread.sleep(400);
log.info("work_queue队列消费者2接收到了消息,消息内容:{}", message);
}
三、 Publish/Subscribe 发布订阅模式
1.发布订阅模式与之前案例的区别就是允许将同一消息发送给多个消费者。实现方式是加入了exchange(交换机),注意:交换机是不缓存消息的
2.使用fanout交换机,会将接收到的消息 路由到每一个跟其绑定的queue (队列)
a.生产者
/**
* 发布订阅
* 一个生产者 多个队列 多个消费者 涉及 到交换机 fanout
*/
@GetMapping("publish/subscribe")
public void publishSubscribe() {
// 第一个参数: 交换机的名称 没有要求
// 第二个参数: 交换机和队列的绑定规则 如果是发布订阅模式 那么这个规则默认不写 只需要交换机和队列绑定即可不需要规则
// 第三个参数: 消息内容
rabbitTemplate.convertAndSend("publish_subscribe_exchange", "",
"hello publisher subscribe!!");
}
b.消费者
@Component
public class PublisherSubscribeConsumer {
private static final Logger log = LoggerFactory.getLogger(PublisherSubscribeConsumer.class);
/**
* 发布订阅模型消费者
*
* @param message
*/
@RabbitListener(bindings = @QueueBinding(value = @Queue("pb_sb_queue_01"),
exchange = @Exchange(name = "publish_subscribe_exchange",
type = ExchangeTypes.FANOUT)))
public void publisherSubscribe(String message) {
log.info("发布订阅模型消费者1接收到了消息,消息内容:{}", message);
}
/**
* 发布订阅模型消费者
*
* @param message
*/
@RabbitListener(bindings = @QueueBinding(value = @Queue("pb_sb_queue_02"),
exchange = @Exchange(name = "publish_subscribe_exchange", type = ExchangeTypes.FANOUT)))
public void publisherSubscribe2(String message) {
log.info("发布订阅模型消费者2接收到了消息,消息内容:{}", message);
}
}
3.门户网站,用户在注册完后一般都会发送消息通知用户注册成功(失败)。 如果在一个系统中,用户注册信息有邮箱、手机号,那么在注册完后会向邮箱和手机号 都发送注册完成信息(假设都发送)。 利用 MQ 实现业务异步处理,如果是用工作队列的话,就会声明一个注册信息队列。注 册完成之后生产者会向队列提交一条注册数据,消费者取出数据同时向邮箱以及手机号 发送两条消息。但是实际上邮箱和手机号信息发送实际上是不同的业务逻辑,不应该放 在一块处理。 这个时候就可以利用发布/订阅模式将消息发送到转换机(EXCHANGE),声明两个不 同的队列(邮箱、手机),并绑定到交换机。这样生产者只需要发布一次消息,两个队 列都会接收到消息发给对应的消费者,大致如下图所示。
四、Routing 路由模式
1.routing模型也是将消息发送到交换机使用的是Direct类型的交换机,会将接收到的消息根据规则路由到指定的Queue(队列),因此称为路由模式
a.生产者
/**
* 路由模型
* 一个生产者 多个队列 多个消费者 涉及 到交换机 direct
*/
@GetMapping("routing")
public void routing() {
// 第一个参数: 交换机的名称 没有要求
// 第二个参数: 交换机和队列的绑定规则 字符串 随意
// 第三个参数: 消息内容
rabbitTemplate.convertAndSend("routing_exchange", "aaa",
"hello routing!!");
}
b.消费者
@Component
@Log4j2
public class RoutingConsumer {
/**
* 路由模型消费者
* @param message
*/
@RabbitListener(bindings = @QueueBinding(value = @Queue("routing_queue_01"),
exchange = @Exchange(name = "routing_exchange", type = ExchangeTypes.DIRECT),
key = { "abc", "error", "info" }))
public void routingConsumer(String message) {
log.info("路由模型消费者1接收到了消息,消息内容:{}", message);
}
/**
* 路由模型消费者
* @param message
*/
@RabbitListener(bindings = @QueueBinding(value = @Queue("routing_queue_02"),
exchange = @Exchange(name = "routing_exchange", type = ExchangeTypes.DIRECT),
key = { "aaa", "ccc", "waadaffas" }))
public void routingConsumer2(String message) {
log.info("路由模型消费者2接收到了消息,消息内容:{}", message);
}
/**
* 路由模型消费者
* @param message
*/
@RabbitListener(bindings = @QueueBinding(value = @Queue("routing_queue_03"),
exchange = @Exchange(name = "routing_exchange", type = ExchangeTypes.DIRECT),
key = { "bbbb", "asdfasd", "asdfasdf" }))
public void routingConsumer3(String message) {
log.info("路由模型消费者3接收到了消息,消息内容:{}", message);
}
}
五、Topics 主题模式
1.topicExchange与directExchange类型,区别在于routingKey必须是多个单词的列表, 并且以 . 分隔,并且包含通配符 * 和 # 。 *(代表通配符,任意一个字段) user.name user.* [user.age, user.xxx] #(号代表一个或多个字段 user.# user.name user.name.age)
a.生产者
/**
* 主题模型
* 一个生产者 多个队列 多个消费者 涉及 到交换机 topic
*/
@GetMapping("topic")
public void topic() {
// 第一个参数: 交换机的名称 没有要求
// 第二个参数: 交换机和队列的绑定规则 多个单词 以 “.” 拼起来
// 第三个参数: 消息内容
rabbitTemplate.convertAndSend("topic_exchange", "cjq.age.name",
"hello topic!!");
}
b.消费者
@Component
@Log4j2
public class TopicConsumer {
/**
* * 表示任意一个单词
* # 表示任意一个单词 或 多个
*/
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic_queue_01"),
exchange = @Exchange(name = "topic_exchange", type = ExchangeTypes.TOPIC),
key = { "abc.*", "error.*.info", "#.name" }))
public void topicConsumer(String message) {
log.info("xxxxxxxxx1");
}
/**
* * 表示任意一个单词
* # 表示任意一个单词 或 多个
*/
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic_queue_02"),
exchange = @Exchange(name = "topic_exchange", type = ExchangeTypes.TOPIC),
key = { "abc.*", "username" }))
public void topicConsumer2(String message) {
log.info("xxxxxxxxx2");
}
/**
* * 表示任意一个单词
* # 表示任意一个单词 或 多个
*/
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic_queue_03"),
exchange = @Exchange(name = "topic_exchange", type = ExchangeTypes.TOPIC),
key = { "cjq.*", "error.*.info" }))
public void topicConsumer3(String message) {
log.info("xxxxxxxxx3");
}
}
六、Publisher Confirms 发布确认模式
就是生产完,确认消费。过几天在弄。
七、其他模式
1.消息转换器:代码里直接发送对象,虽然接收的到消息,但是rabbitmq的界面上看到的消息会是乱码,这样就不用必须是String字符串或者byte[]数组和序列化后的对象了。再次发送就会是转换好的消息
依赖
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.9.10</version>
</dependency>
配置
@Configuration
public class RabbitmqConfig {
// 消息转换配置
@Bean
public MessageConverter jsonMessageConverter(){
return new Jackson2JsonMessageConverter();
}
}
当然,还有其他很多种模式,延迟队列、TTL队列、死信队列等等,过几天再给大家详细介绍。