什么是MQ?【熟悉】
-
定义:MessageQueue消息队列
-
组成:
- 中间件:队列载体
- 生产者
- 消费者
-
优势
- 应用解耦:提供了程序的可扩展性
- 异步提速:提高了系统的性能
- 削峰填谷:提升了系统的稳定性
-
劣势
- 增加了系统维护成本
- 系统可用性降低(忽略)
-
场景的产品
- Pulsar 最新流行
什么是Rabbitmq
-
定义:是一个基于AMQP协议实现的一款消息中间件
-
组成:
Rabbitmq API发送消息[精通]
-
建立连接
//1.创建连接工厂===================== ConnectionFactory factory = new ConnectionFactory(); //2. 设置参数 factory.setHost("172.16.98.133");//ip 默认值 localhost factory.setPort(5672); //端口 默认值 5672 factory.setVirtualHost("/itcast");//虚拟机 默认值/ factory.setUsername("heima");//用户名 默认 guest factory.setPassword("heima");//密码 默认值 guest //3. 创建连接 Connection Connection connection = factory.newConnection(); //4. 创建Channel============================== Channel channel = connection.createChannel();
-
业务处理:向一个队列中发送消息
-
创建队列
/* 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"),通配符的方式 3. durable:是否持久化 4. autoDelete:自动删除,没有队列的 5. internal:内部使用。 一般false 6. arguments:参数 */ String exchangeName = "test_fanout"; //5. 创建交换机 channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT,true,false,false,null);
-
绑定队列和交换机
//6. 创建队列 String queue1Name = "test_fanout_queue1"; String queue2Name = "test_fanout_queue2"; channel.queueDeclare(queue1Name,true,false,false,null); channel.queueDeclare(queue2Name,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,"");
-
发送消息
/* 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()); //pub、sub模式 channel.basicPublish(exchangeName,"",null,body.getBytes());
-
-
释放连接
channel.close(); connection.close();
Rabbitmq API监听消息[精通]
-
建立连接
//1.创建连接工厂===================== ConnectionFactory factory = new ConnectionFactory(); //2. 设置参数 factory.setHost("172.16.98.133");//ip 默认值 localhost factory.setPort(5672); //端口 默认值 5672 factory.setVirtualHost("/itcast");//虚拟机 默认值/ factory.setUsername("heima");//用户名 默认 guest factory.setPassword("heima");//密码 默认值 guest //3. 创建连接 Connection Connection connection = factory.newConnection(); //4. 创建Channel============================== Channel channel = connection.createChannel();
-
处理业务逻辑
-
监听消息队列
/* basicConsume(String queue, boolean autoAck, Consumer callback) 参数: 1. queue:队列名称 2. autoAck:是否自动确认 3. callback:回调对象 */ channel.basicConsume("hello_world",true,consumer);
-
处理消息
// 接收消息 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)); } };
-
-
释放连接
- 消费端一般不主动关闭
Rabbitmq的5中使用方式【精通】
- QUEUE存在多个消费者时,其消费者之间是轮询获取消息的方式
名称 | exchange | routingkey | 消费者数量 |
---|---|---|---|
simple | 默认交换机 | 队列名称 | 1 |
work | 默认交换机 | 队列名称 | N |
pub/sub | 自定义(fanout) | “” | N |
routing | 自定义(driect) | 自定义全名称 | N |
topic | 自定义(topic) | 支持通配符 | N |
- #:0或者多级的匹配
- *:一级的匹配
Spring集成Rabbitmq生产端【熟悉】
-
导包
<dependency> <groupId>org.springframework.amqp</groupId> <artifactId>spring-rabbit</artifactId> <version>2.1.8.RELEASE</version> </dependency>
-
配置
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:rabbit="http://www.springframework.org/schema/rabbit" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd"> <!--加载配置文件--> <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}"/> <!--定义管理交换机、队列--> <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="heima.*" queue="spring_topic_queue_star"/> <rabbit:binding pattern="heima.#" queue="spring_topic_queue_well"/> <rabbit:binding pattern="itcast.#" queue="spring_topic_queue_well2"/> </rabbit:bindings> </rabbit:topic-exchange> <!--定义rabbitTemplate对象操作可以在代码中方便发送消息--> <rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"/> </beans>
-
编码
//1.注入 RabbitTemplate @Autowired private RabbitTemplate rabbitTemplate; @Test public void testHelloWorld(){ //2.发送消息 rabbitTemplate.convertAndSend("spring_queue","hello world spring...."); }
Spring集成Rabbitmq消费端【熟悉】
-
导包与生产端一致
-
配置
<bean id="springQueueListener" class="com.itheima.rabbitmq.listener.SpringQueueListener"/> <rabbit:listener-container connection-factory="connectionFactory" auto-declare="true"> <rabbit:listener ref="springQueueListener" queue-names="spring_queue"/> </rabbit:listener-container>
-
编码
- 需要实现MessageListener接口
public class SpringQueueListener implements MessageListener { @Override public void onMessage(Message message) { //打印消息 System.out.println(new String(message.getBody())); } }
SpringBoot集成Rabbitmq【精通】
-
导包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
-
配置
spring: rabbitmq: host: localhost # ip port: 5672 username: guest password: guest virtual-host: /
-
编码
- 发送
//1.注入RabbitTemplate @Autowired private RabbitTemplate rabbitTemplate; @Test public void testSend(){ rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME,"boot.haha","boot mq hello~~~"); }
- 监听
@Component public class AckListener { @RabbitListener(queues = "TOPIC_QUEUE_SPRINGBOOT_1") public void onMessage(Message message,Channel channel) throws IOException { } }
SpringBoot中JavaConfig方式声明队列、交换信息【精通】
- QueueBuilder:声明queue构建器
- ExchangeBuilder:声明交换机构建器
- BindingBuilder:声明绑定关系构建器
//1.交换机
@Bean
public Exchange bootExchange(){
return ExchangeBuilder.topicExchange(EXCHANGE_NAME).durable(true).build();
}
//2.Queue 队列
@Bean
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();
}
Queue 队列
@Bean
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();
}