什么是MQ?【熟悉】
-
定义:MessageQueue,消息队列
-
应用场景:
-
在微服务之间进行消息通信
-
优势:
- 应用解耦:提高系统的容错性和可扩展性
- 异步提速:提高系统的吞吐量
- 削峰填谷:提高系统的高可用
-
劣势:
- 系统复杂度提高
-
相关产品
什么是RabbitMQ?【精通】
- 定义:是一个实现了AMQP协议的消息中间件产品(AMQP是一个类似于http,用于网络传输数据格式组织的协议)
- 组成:
- producer(生产者):发送消息
- channel(管道):用于同时读写消息,提升与broker通信效率的
- consumer(消费者):接收消息
- channel(管道):用于同时读写消息,提升与broker通信效率的
- broker(一台Rabbitmq的服务器):存储和路由消息
- VirtualHost:虚拟主机,作用类似mysql的database,用于隔离不同虚拟主机下的消息互相不影响
- exchage:交互机,分发消息到队列
- queue:队列,用于存储消息
- Binding动作:把exchage与queue绑定在一起的过程
- routingkey:消息的分发过滤条件
- VirtualHost:虚拟主机,作用类似mysql的database,用于隔离不同虚拟主机下的消息互相不影响
- producer(生产者):发送消息
什么是JMS?
- 定义:jms一套java提供的用于消息发送和接收的API接口
Docker安装rabbitmq
docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management
使用原生API来发送消息的步骤【精通】
-
建立连接 —可以定义一个connection工具类
-
创建连接工厂ConnectionFactory
- VirtualHost
- username
- password
- host
- port
ConnectionFactory factory = new ConnectionFactory(); //2. 设置参数 factory.setHost("172.16.98.133");//ip 默认值 localhost factory.setPort(5672); //端口 默认值 5672 factory.setVirtualHost("/");//虚拟机 默认值/ factory.setUsername("roc");//用户名 默认 guest factory.setPassword("roc");//密码 默认值 guest
-
获取Channel
//3. 创建连接 Connection Connection connection = factory.newConnection(); //4. 创建Channel Channel channel = connection.createChannel();
-
-
消息发送
- 发送消息
/* basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) 参数: 1. exchange:交换机名称。简单模式下交换机会使用默认的 "" 2. routingKey:路由名称 3. props:配置信息 4. body:发送消息数据 */ String body = "hello rabbitmq~~~"; //6. 发送消息simple\work channel.basicPublish("","hello_world",null,body.getBytes()); //8. 发送消息fanout channel.basicPublish(exchangeName,"",null,body.getBytes());
-
资源释放
channel.close(); connection.close();
使用原生API来接收消息的步骤【精通】
- 建立连接(参考发送)
- 消息接收
/*
basicConsume(String queue, boolean autoAck, Consumer callback)
参数:
1. queue:队列名称
2. autoAck:是否自动确认
3. callback:当时收到消息后,怎么处理消息
*/
// 接收消息
Consumer consumer = new DefaultConsumer(channel){
/*
回调方法,当收到消息后,会自动执行该方法
1. consumerTag:标识
2. envelope:获取一些信息,交换机,路由key...
3. properties:配置信息
4. body:数据
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("consumerTag:"+consumerTag);
System.out.println("Exchange:"+envelope.getExchange());
System.out.println("RoutingKey:"+envelope.getRoutingKey());
System.out.println("properties:"+properties);
System.out.println("body:"+new String(body));
}
};
channel.basicConsume("hello_world",true,consumer);
API创建队列或交换机
- 创建队列
/*
queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
参数:
1. queue:队列名称
2. durable:是否持久化,当mq重启之后,还在
3. exclusive:
* 是否独占。只能有一个消费者监听这队列
* 当Connection关闭时,是否删除队列
*
4. autoDelete:是否自动删除。当没有Consumer时,自动删除掉
5. arguments:参数。
*/
//如果没有一个名字叫hello_world的队列,则会创建该队列,如果有则不会创建
channel.queueDeclare("hello_world",true,false,false,null);
- 创建交换机
/*
exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments)
参数:
1. exchange:交换机名称
2. type:交换机类型
DIRECT("direct"),:定向
FANOUT("fanout"),:扇形(广播),发送消息到每一个与之绑定队列。
TOPIC("topic"),通配符的方式
HEADERS("headers");参数匹配
3. durable:是否持久化
4. autoDelete:自动删除:没有一个队列与其绑定时,自动删除
5. internal:内部使用。 一般false
6. arguments:参数
*/
String exchangeName = "test_fanout";
//5. 创建交换机
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT,true,false,false,null);
- 绑定交换机与队列
//7. 绑定队列和交换机
/*
queueBind(String queue, String exchange, String routingKey)
参数:
1. queue:队列名称
2. exchange:交换机名称
3. routingKey:路由键,绑定规则
如果交换机的类型为fanout ,routingKey设置为""
*/
channel.queueBind(queue1Name,exchangeName,"");
channel.queueBind(queue2Name,exchangeName,"");
Rabbitmq的5中工作模式【精通】
- 一个队列可以有多个消费者,但是一条消息同时只能被一个消费者处理。默认队列路由给消费者的策略是轮询。
- 通配符
- *:单级匹配
- ##:多级匹配,类似之前学习的/**
- 交换机与队列的关系:是多对多关系
- 一个交换机可以绑定多个队列
- 一个队列可以绑定到多个交换机
- 一个队列可多次绑定到同个交换机
名称 | 交换机 | 消费者数量 | 路由key | |
---|---|---|---|---|
simple模式 | 默认交换机 | 1个 | 队列名称 | |
work模式 | 默认交换机 | 多个 | 队列名称 | |
订阅模式 | 广播模式,fanout | 自定义fanout | 多个 | 无 |
订阅模式 | 路由模式,routing | 自定义direct | 多个 | 自定义key |
订阅模式 | 主题模式,topic | 自定义topic | 多个 | 自定义key,可以使用通配符 |
Spring整合Ribbtmq【熟悉】
- 导包
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>
-
配置
- 初始化RabbitTemplate
<!--加载配置文件--> <context:property-placeholder location="classpath:rabbitmq.properties"/> <!-- 定义rabbitmq connectionFactory --> <rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}" port="${rabbitmq.port}" username="${rabbitmq.username}" password="${rabbitmq.password}" virtual-host="${rabbitmq.virtual-host}"/> <!--定义rabbitTemplate对象操作可以在代码中方便发送消息--> <rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"/>
- 创建队列和交换机[可选]
<!--定义管理交换机、队列--> <rabbit:admin connection-factory="connectionFactory"/> <!--定义持久化队列,不存在则自动创建;不绑定到交换机则绑定到默认交换机 默认交换机类型为direct,名字为:"",路由键为队列的名称 --> <!-- id:bean的名称 name:queue的名称 auto-declare:自动创建 auto-delete:自动删除。 最后一个消费者和该队列断开连接后,自动删除队列 exclusive:是否独占 durable:是否持久化 --> <rabbit:queue id="spring_queue" name="spring_queue" auto-declare="true"/> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~广播;所有队列都能收到消息~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <!--定义广播交换机中的持久化队列,不存在则自动创建--> <rabbit:queue id="spring_fanout_queue_1" name="spring_fanout_queue_1" auto-declare="true"/> <!--定义广播交换机中的持久化队列,不存在则自动创建--> <rabbit:queue id="spring_fanout_queue_2" name="spring_fanout_queue_2" auto-declare="true"/> <!--定义广播类型交换机;并绑定上述两个队列--> <rabbit:fanout-exchange id="spring_fanout_exchange" name="spring_fanout_exchange" auto-declare="true"> <rabbit:bindings> <rabbit:binding queue="spring_fanout_queue_1" /> <rabbit:binding queue="spring_fanout_queue_2"/> </rabbit:bindings> </rabbit:fanout-exchange> <!--<rabbit:direct-exchange name="aa" > <rabbit:bindings> <!–direct 类型的交换机绑定队列 key :路由key queue:队列名称–> <rabbit:binding queue="spring_queue" key="xxx"></rabbit:binding> </rabbit:bindings> </rabbit:direct-exchange>--> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~通配符;*匹配一个单词,#匹配多个单词 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <!--定义广播交换机中的持久化队列,不存在则自动创建--> <rabbit:queue id="spring_topic_queue_star" name="spring_topic_queue_star" auto-declare="true"/> <!--定义广播交换机中的持久化队列,不存在则自动创建--> <rabbit:queue id="spring_topic_queue_well" name="spring_topic_queue_well" auto-declare="true"/> <!--定义广播交换机中的持久化队列,不存在则自动创建--> <rabbit:queue id="spring_topic_queue_well2" name="spring_topic_queue_well2" auto-declare="true"/> <rabbit:topic-exchange id="spring_topic_exchange" name="spring_topic_exchange" auto-declare="true"> <rabbit:bindings> <rabbit:binding pattern="roc.*" queue="spring_topic_queue_star"/> <rabbit:binding pattern="roc.#" queue="spring_topic_queue_well"/> <rabbit:binding pattern="ou.#" queue="spring_topic_queue_well2"/> </rabbit:bindings> </rabbit:topic-exchange>
-
编码
- 接收消息
<bean id="springQueueListener" class="com.roc.rabbitmq.listener.SpringQueueListener"/> <rabbit:listener-container connection-factory="connectionFactory" auto-declare="true"> <rabbit:listener ref="springQueueListener" queue-names="spring_queue"/> </rabbit:listener-container>
import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessageListener; public class SpringQueueListener implements MessageListener { @Override public void onMessage(Message message) { //打印消息 System.out.println(new String(message.getBody())); } }
- 发送消息
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void testHelloWorld(){
//2.发送消息
rabbitTemplate.convertAndSend("spring_queue","hello world spring....");
}
SpringBoot整合Rabbitmq【精通】
- 导包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
- 配置
# 配置RabbitMQ的基本信息 ip 端口 username password..
spring:
rabbitmq:
host: 172.16.98.133 # ip
port: 5672
username: guest
password: guest
virtual-host: /
-
编码
- 接收消息
@Component public class RabbimtMQListener { @RabbitListener(queues = "boot_queue") public void ListenerQueue(Message message, Channel channel){ //System.out.println(message); System.out.println(new String(message.getBody())); } }
- 发送消息
//1.注入RabbitTemplate
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void testSend(){
rabbitTemplate.convertAndSend("boot_topic_exchange","boot.haha","boot mq hello~~~");
}
SpringBoot使用JavaConfig来创建交换机和队列【精通】
- ExchangeBuilder:创建交换机
- QueueBuilder:创建队列
- BindingBuilder:创建绑定关系
//1.交换机
@Bean("bootExchange")
public Exchange bootExchange(){
return ExchangeBuilder.topicExchange(EXCHANGE_NAME).durable(true).build();
}
//2.Queue 队列
@Bean("bootQueue")
public Queue bootQueue(){
return QueueBuilder.durable(QUEUE_NAME).build();
}
//3. 队列和交互机绑定关系 Binding
/*
1. 知道哪个队列
2. 知道哪个交换机
3. routing key
*/
@Bean
public Binding bindQueueExchange(@Qualifier("bootQueue") Queue queue, @Qualifier("bootExchange") Exchange exchange){
return BindingBuilder.bind(queue).to(exchange).with("boot.#").noargs();
}
urable(true).build();
}
//2.Queue 队列
@Bean("bootQueue")
public Queue bootQueue(){
return QueueBuilder.durable(QUEUE_NAME).build();
}
//3. 队列和交互机绑定关系 Binding
/*
1. 知道哪个队列
2. 知道哪个交换机
3. routing key
*/
@Bean
public Binding bindQueueExchange(@Qualifier("bootQueue") Queue queue, @Qualifier("bootExchange") Exchange exchange){
return BindingBuilder.bind(queue).to(exchange).with("boot.#").noargs();
}