首先学习先得有环境搭建与部署
linux部署RabbitMQ请参考linux 安装RebbitMQ3.86_yuell102的博客-CSDN博客
开发工具用的是idea
java是jdk11
pom.xml中必须包含
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
application.yml 配置rabbitmq服务器的参数
spring:
application:
name: rabbitmq-spring
rabbitmq:
host: xxxx
port: xxxx
username: xxx
password: xxx
virtual-host: /
第一种模型
创建消费者
@Component
@RabbitListener(queuesToDeclare = @Queue("hello"),
declare = "true",
autoDelete = "false")//@RabbitListener消费队列 @Queue 队列名称 declare 是否持久化 autoDelete 是否自动删除
public class HelloCustomer {
@RabbitHandler//处理消息的回调方法
public void receivel(String msg){
System.out.println(msg);
}
}
创建生产者
@SpringBootTest(classes = RabbitmqApplication.class)
class RabbitmqApplicationTests {
@Autowired//spring对类成员变量、方法及构造函数进行标注,完成自动装配的工作
private RabbitTemplate rabbitTemplate;//springboot为我们封装的rabbitmq
@Test
public void test() {
rabbitTemplate.convertAndSend("hello", "你好");//发布消息
//routingKey hello
//hello 为队列名称
//object 你好
//你好 具体消息
}
}
convertSendAndReceive(…):可以同步消费者。使用此方法,当确认了所有的消费者都接收成功之后,才触发另一个convertSendAndReceive(…),也就是才会接收下一条消息。RPC调用方式。
convertAndSend(…):使用此方法,交换机会马上把所有的信息都交给所有的消费者,消费者再自行处理,不会因为消费者处理慢而阻塞线程。
这里要注意,一定要先启动消费者
没有消费者不会构建Queues
运行完后
已经构建出了 hello Queues
并且已经被消费
第二种模型
生产者
@SpringBootTest(classes = RabbitmqApplication.class)
class RabbitmqApplicationTests {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void work() {
for (int i = 0; i < 10; i++) {
rabbitTemplate.convertAndSend("work", "我是work生成者"+i);
}
}
// @Test
// public void test() {
// rabbitTemplate.convertAndSend("hello", "你好");
// }
}
消费者
@Component
public class WorkCustomer {
@RabbitListener(queuesToDeclare = @Queue("work"))
public void work1(String msg){
System.out.println("消费者work1" + msg);
}
@RabbitListener(queuesToDeclare = @Queue("work"))
public void work2(String msg) throws InterruptedException {
Thread.sleep(2000);
System.out.println("消费者work2" + msg);
}
}
一个生产者 对多个消费者运行结果
第三种模型
发布者
@SpringBootTest(classes = RabbitmqApplication.class)
class RabbitmqApplicationTests {
@Autowired
private RabbitTemplate rabbitTemplate;
public void fanot(){
rabbitTemplate.convertAndSend("logs", "", "fanot模型发送的消息");
}
// @Test
// public void work() {
// for (int i = 0; i < 10; i++) {
// rabbitTemplate.convertAndSend("work", "我是work生成者"+i);
// }
// }
// @Test
// public void test() {
// rabbitTemplate.convertAndSend("hello", "你好");
// }
}
订阅者
@Component
public class FanoutCustomer {
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "logs", type = "fanout")
)
})
public void fanout1(String msg){
System.out.println("msg1 = " + msg);
}
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "logs", type = "fanout")
)
})
public void fanout2(String msg){
System.out.println("msg2 = " + msg);
}
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "logs", type = "fanout")
)
})
public void fanout3(String msg){
System.out.println("msg3 = " + msg);
}
}
运行结果
与前两者的模式相比,此模式是临时队列,主要交换机处理,同一个消息订阅者都能接收到
第四种模式
根据路由key订阅消息
生产者
@SpringBootTest(classes = RabbitmqApplication.class)
class RabbitmqApplicationTests {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void direct(){
rabbitTemplate.convertAndSend("directs", "info", "发送的是info路由消息");
}
}
消费者
@Component
public class RouteCustomer {
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "directs", type = "direct"),
key = {"info"}
)
})
public void directs1(String msg){
System.out.println("directs1" + msg);
}
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "directs", type = "direct"),
key = {"info","error"}
)
})
public void directs2(String msg){
System.out.println("directs2" + msg);
}
}
运行结果
修改消费者后
@SpringBootTest(classes = RabbitmqApplication.class)
class RabbitmqApplicationTests {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void direct(){
rabbitTemplate.convertAndSend("directs", "error", "发送的是info路由消息");
}
}
运行结果
第五种模式
生产者
@SpringBootTest(classes = RabbitmqApplication.class)
class RabbitmqApplicationTests {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void topic(){
rabbitTemplate.convertAndSend("topics", "user.save", "user.save的路由消息");
}
}
消费者
@Component
public class RouteCustomer {
//# 代表一个或者多个
//* 代表一个
//每个可以以.分割
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(type = "topic", name = "topics"),
key = {"user.save", "user.*"}
)
})
public void topics1(String msg){
System.out.println("topics1" + msg);
}
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(type = "topic", name = "topics"),
key = {"#.save", "user.#", "user.insert"}
)
})
public void topics2(String msg){
System.out.println("topics2" + msg);
}
}
运行结果
修改生产者后
@SpringBootTest(classes = RabbitmqApplication.class)
class RabbitmqApplicationTests {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void topic(){
rabbitTemplate.convertAndSend("topics", "save", "user.save的路由消息");
}
}
运行结果
手动配置yml
spring:
rabbitmq:
host: 192.168.0.48
port: 5672
username: admin
password: 123456
listener:
type: simple
simple:
acknowledge-mode: auto
# acknowledge-mode: manual #手动
# default-requeue-rejected: true #异常或者拒绝重新回到队列
retry:
# max-attempts: 5 #重发次数
enabled: true #允许重发
max-interval: 10000 #重试最大间隔时间
initial-interval: 2000 #重试初始间隔时间
multiplier: 2 #间隔时间乘子,间隔时间*乘子=下一次的间隔时间,最大不能超过设置的最大间隔时间
消息确认
@RabbitListener(queues = "${customs.declare.send_queue}")
@RabbitHandler
public void sendProcess(@Payload String message, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) throws IOException {
//消息为null 过滤掉
if (StringUtils.isEmpty(message)) return;
//获取数据
JSONObject json = JSONObject.parseObject(message);
//获取key
String key = json.keySet().iterator().next();
//获取文本内容
String msg = json.get(key).toString();
//添加后缀名
String fileName = key + XML;
log.info("开始向tosend文件夹写入文件:{}", fileName);
//创建FTP并建立连接
FtpUtil ftpCli = FtpUtil.createFtpCli(hostname, port, username, password, "UTF-8");
ftpCli.connect();
if (StringUtils.isNotEmpty(ftpCli)
&& ftpCli.upload(tosend, fileName, msg)) {
log.info("tosend文件:{} 写入完成", fileName);
//消息确认
channel.basicAck(deliveryTag,false);
} else {
log.error("tosend文件:{} 写入失败", fileName);
}
log.info("结束向tosend文件夹写入:{}", fileName);
}