目录
1.消息中间件
1.1消息队列中间件简介
消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题实现高性能,高可用,可伸缩和最终一致性[架构] 使用较多的消息队列有 ActiveMQ, RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ
发送消息速度: Kafaka (RocketMQ) > RabbitMQ > ActiveMQ
稳定性: ActiveMQ > RabbitMQ > Kafaka (RocketMQ)
1.2RabbitMQ架构图
Producer: 消息生产者,如图A
、
B
、C。
Exchange:交换器,生产者将消息发送到 Exchange。
Queue
:(队列)是
RabbitMQ
的内部对象,用于存储消息。
Consumer
:消息消费者,如图
1
、
2
、3。
1.3RabbitMQ安装
这里我用的是linux环境,介绍下再docker下安装
(
1
)下载镜像:
docker pull rabbitmq:management
(2)创建容器,rabbitmq 需要有映射以下端口: 5671 5672 4369 15671 15672
25672
docker run -di --name=tensquare_rabbitmq -p 5671:5617 -p 5672:5672 -p 4369:4369 -p 15671:15671 -p 15672:15672 -p 25672:25672 rabbitmq:management
如图,浏览器访问 http://ip地址:15672/
1.4RabbitMQ 三种消息模式
1.4.1直接模式(Direct)
我们需要将消息发给唯一一个节点时使用这种模式,这是最简单的一种形式。
任何发送到
DirectExchange
的消息都会被转发到
RouteKey
中指定的
Queue
。
1.
一般情况可以使用
rabbitMQ
自带的
Exchange
:”
"(
该
Exchange
的名字为空字符串,下
文称其为
defaultExchange)
。
2.
这种模式下不需要将
Exchange
进行任何绑定
(binding)
操作
3.
消息传递时需要一个“
RouteKey
”,可以简单的理解为要发送到的队列名字。
4.
如果
vhost
中不存在
RouteKey
中指定的队列名,则该消息会被抛弃。
步骤
新建队列
1.4.2分列模式(Fanout)
当我们需要将消息一次发给多个队列时,需要使用这种模式。如下图:
任何发送到
FanoutExchange
的消息都会被转发到与该
Exchange
绑定
(Binding)
的所有
Queue
上。
1.
可以理解为路由表的模式
2.
这种模式不需要
RouteKey
3.
这种模式需要提前将
Exchange
与
Queue
进行绑定,一个
Exchange
可以绑定多个
Queue
,一个
Queue
可以同多个
Exchange
进行绑定。
4.
如果接受到消息的
Exchange
没有与任何
Queue
绑定,则消息会被抛弃
。
步骤
(1)新建交换器
(2)点击我们新建的交换器,绑定queue队列
1.4.3主题模式
任何发送到
TopicExchange
的消息都会被转发到所有关心
RouteKey
中指定话题的
Queue
上
如上图所示
此类交换器使得来自不同的源头的消息可以到达一个对列,其实说的更明白一点就是模糊匹配的意思,例如:上图中红色对列的routekey为usa.#,#代表匹配任意字符,但是
要想消息能到达此对列,usa.
必须匹配后面的
#
好可以随意。图中
usa.news
usa.weather,
都能找到红色队列,符号
#
匹配一个或多个词,符号
*
匹配不多不少一个词。因此usa.#
能够匹配到
usa.news.XXX
,但是
usa.*
只会匹配到
usa.XXX
。
注:
交换器说到底是一个名称与队列绑定的列表。当消息发布到交换器时,实际上是由你所连接的信道,将消息路由键同交换器上绑定的列表进行比较,最后路由消息。任何发送到TopicExchange
的消息都会被转发到所有关心
RouteKey
中指定话题的Queue上
1.
这种模式较为复杂,简单来说,就是每个队列都有其关心的主题,所有的消息都带有一个“标题”(RouteKey)
,
Exchange
会将消息转发到所有关注主题能与
RouteKey
模糊匹配的队列。
2.
这种模式需要
RouteKey
,也需要提前绑定
Exchange
与
Queue
。
3.
在进行绑定时,要提供一个该队列关心的主题,如“
#.log.#
”表示该队列关心所有涉及log的消息
(
一个
RouteKey
为”
MQ.log.error
”的消息会被转发到该队列
)
。“#
”表示
0
个或若干个关键字,“”表示一个关键字。如“
log.
”能与“
log.warn
”匹配,无法与“log.warn.timeout
”匹配;但是“
log.#
”能与上述两者匹配。
4.
同样,如果
Exchange
没有发现能够与
RouteKey
匹配的
Queue
,则会抛弃此消息
步骤
新建主题交换器
点击我们新建好的交换器
2.三种模式开发步骤
项目结构
2.1pom.xml加入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itcast</groupId>
<artifactId>rabbitmqDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
2.2resources新增application.yml
server:
port: 8082
spring:
rabbitmq:
host: 127.0.0.1
2.3启动类
package com.itast.rabbitmq;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MQApplication {
public static void main(String[] args) {
SpringApplication.run(MQApplication.class,args);
}
}
2.4编写消息生产者
package com.itcast.rabbitmq;
import com.itast.rabbitmq.MQApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate;
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(classes = MQApplication.class)
public class MqTest {
@Autowired
private RabbitMessagingTemplate rabbitMessagingTemplate;
/***
* 直接模式-消费者
* */
@Test
public void testDirect() {
rabbitMessagingTemplate.convertAndSend("itcast", "直接模式测试");
}
/**
* 分列模式
*/
@Test
public void testFanout() {
rabbitMessagingTemplate.convertAndSend("testFanout1", "", "分列模式测试");
}
/**
* 主题模式
*/
@Test
public void testTopic(){
rabbitMessagingTemplate.convertAndSend("testTopic","goods.new","主题模式测试");
}
}
2.5编写消息消费者1
package com.itast.rabbitmq.consumer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
@RabbitListener(queues = "itcast")
public class Consumer {
@RabbitHandler
public void sendMessage(String msg){
System.out.println("接收到的消息"+msg);
}
}
2.6编写消息消费者2
package com.itast.rabbitmq.consumer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/***
* 分列模式-消费者
*/
@Component
@RabbitListener(queues = "itheima")
public class Consumer2 {
@RabbitHandler
public void sendMessage(String msg){
System.out.println("itheima接收到的消息======"+msg);
}
}
2.7编写消息消费者3
package com.itast.rabbitmq.consumer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/***
* 分列模式-消费者
*/
@Component
@RabbitListener(queues = "test")
public class Consumer3 {
@RabbitHandler
public void sendMessage(String msg){
System.out.println("test接收到的消息======"+msg);
}
}