安装RabbitMQ
docker run -d --name rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p 25672:25672 -p 15671:15671 -p 15672:15672 rabbitmq:management
4369, 25672 (Erlang发现&集群端口)
5672, 5671 (AMQP端口) 5672高级消息协议工作的端口 也是客户端要连接的端口
15672 (web管理后台端口)
61613, 61614 (STOMP协议端口)
1883, 8883 (MQTT协议端口)
发消息是发给消息代理(安装了消息中间件的服务器)的交换机,监听是监听的队列,交换机把消息放入队列
springboot整合RabbitMQ
一般引入依赖 就能搜到一些自动配置类 RabbitAutoConfiguration 可以尝试搜一下这种xxxxAutoConfiguration
在这个RabbitAutoConfiguration 里又注入了一些Bean 什么AmqpAdmin 一般创建一个对象会有xxxFactory这种嘛 又可以尝试找一下
找到了发现里面的有些参数是根据 RabbitPropertie这个类来的 点进去发现 prefix = “spring.rabbitmq” 说明我们可能要在配置文件里以这种前缀配置 然后再用AmqpAdmin 来创建 exchange交换机 queue队列 Binding绑定关系这些 这就对使用java api来操作 RabbitMQ有一个了解
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
启动类
@EnableRabbit
测试类
package com.kaki.gulimall.order;
import com.kaki.gulimall.order.entity.OrderReturnReasonEntity;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class GulimallOrderApplicationTests {
@Autowired
AmqpAdmin amqpAdmin;
@Autowired
RabbitTemplate rabbitTemplate;
/**
* 测试消息队列 只要引入依赖 就会有 RabbitAutoConfiguration.java
* 如何使用java api 创建 exchange交换机 queue队列 Binding绑定关系 使用 AmqpAdmin进行创建
*/
@Test
public void createExchange() {
DirectExchange directExchange = new DirectExchange("java.direct.exchange",true,false);
amqpAdmin.declareExchange(directExchange);
log.info("Exchange【{}】创建成功。。。","java.direct.exchange");//这里占位符不用加0吗 我记得之前要{0}
}
@Test
public void createQueue(){
Queue queue = new Queue("java.queue",true,false,false);
amqpAdmin.declareQueue(queue);
log.info("Queue【{}】创建成功。。。","java.queue");
}
@Test
public void createBinding(){
//String destination, 目的地
// Binding.DestinationType destinationType, 目的地类型 交换机还是队列
// String exchange, 源交换机
// String routingKey, 路由键
// Map<String, Object> arguments参数
Binding binding = new Binding("java.queue", Binding.DestinationType.QUEUE,
"java.direct.exchange","java.lalala",null);
amqpAdmin.declareBinding(binding);
log.info("Binding创建成功。。。");
}
/**
* 发送 消息 RabbitTemplate 消息是发给交换机的 消息是有路由键的
*/
@Test
public void sendMessage(){
//String exchange, String routingKey, Object object
//发消息可以发一段字符串 也可以发一个对象 对象会被序列化 不想序列化可以自己注入一个MessageConverter
OrderReturnReasonEntity orderReturnReasonEntity = new OrderReturnReasonEntity();
orderReturnReasonEntity.setName("lalala");
orderReturnReasonEntity.setSort(1);
orderReturnReasonEntity.setStatus(1);
// rabbitTemplate.convertAndSend("java.direct.exchange","java.aaa"
// ,"我是消息内容");
rabbitTemplate.convertAndSend("java.direct.exchange","java.lalala"
,orderReturnReasonEntity);
}
/**
* 接收消息的方法 需要使用 @RabbitListener 注解 这个注解可以放在业务逻辑组件 Service上
* 这个service 组件 必须放在容器中(加 @Sevice注解) @RabbitListener 注解才能起作用
* 比如 我们就把接收消息的方法放在 OrderItemServiceImpl 中
*/
}
配置对象以json的方式存在消息里
package com.kaki.gulimall.order.config;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyRabbitConfig {
/**
* RabbitMQ 如果发送的消息是字符串就直接发送
* 如果发送的消息是对象 首先去容器中找有没有MessageConverter 如果没有源码就自己创建了
* 一个SimpleMessageConverter 会把对象序列化成字节数组 byte[] 存在消息里
* 想让对象数据可见性更好 我们就可以自己注入一个把对象转成json的MessageConverter
*/
@Bean
public MessageConverter messageConverter(){
// ctrl+h 查看MessageConverter的实现类可以发现有下面这个
return new Jackson2JsonMessageConverter();
}
}
接收消息
* 在RunDashBoard 选择这个服务 copy configuration 把当前这个订单服务启动多个
* 测试类那边循环发送多个消息 可以发现同一个消息 只能被一个订单服务(客户端)接收到
*
* 只有等一个消息处理完了 才能接收下一个消息 被接收的消息从队列里删除
package com.kaki.gulimall.order.service.impl;
import com.kaki.gulimall.order.entity.OrderReturnReasonEntity;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
@Service("orderItemService")
public class OrderItemServiceImpl extends ServiceImpl<OrderItemDao, OrderItemEntity> implements OrderItemService {
@RabbitListener(queues = {"java.queue"})//表示要监听哪个队列的消息 可以监听多个队列
public void receiveMessage(Message message,
OrderReturnReasonEntity entity,
Channel channel){//开始不知道消息类型的话可以用Object message.getClass()打印消息的类
//发现是 Message类 也可以直接写 OrderReturnReasonEntity 来接收消息 因为我们那边发消息就是传的 这个类的对象嘛
//拿到消息体
byte[] body = message.getBody();
//拿到消息头
MessageProperties messageProperties = message.getMessageProperties();
System.out.println("接收的消息为:"+message+",消息类型为:"+message.getClass());
System.out.println(entity);
}
}