前言在上一篇我们对RabbitMQ有了一个最基本的认识和了解,和对一些主流中间键的选型,本篇我们会去带大家使用RabbitMQ,完成基本的通信,还没有看过RabbitMQ基础的同学可以去看看哦!https://blog.csdn.net/m0_58046039?spm=1000.2115.3001.5343
1.搭建项目导入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.4</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.6.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
2.准备一个controller发送消息(controller相当于生产者)
2.1使用MQ实现消息发送
2.1大致步骤:创建工厂,设置端口,建立与Broker的TCP连接,创建信道,发送消息,其中我们用的一个序列化类ObjectMapper,这里是因为MQ发送消息时底层是子节码,所以这里用了它
package com.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.po.UserPo;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 相当于生产者
* @Author sj
* @Date: 2022/04/18/ 10:58
* @Description
*/
@RestController
public class ProducerController {
/**
* 序列化类
*/
private ObjectMapper objectMapper = new ObjectMapper();
/**
* 模拟MQ发送消息
* @param userPo
*/
@PostMapping("/send")
public void sendNews(@RequestBody UserPo userPo) throws JsonProcessingException {
// 获取连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
// 设置端口
connectionFactory.setHost("localhost");
// 获取于Broker的TCP连接connection
Connection connection;
// 序列化对象
String body = objectMapper.writeValueAsString(userPo);
// 获取字节码,因为MQ底层是使用字节码传输,方便下面使用
byte[] bytes = body.getBytes();
try {
connection = connectionFactory.newConnection();
// 创建信道
Channel channel = connection.createChannel();
// 向交换机发送消息
channel.basicPublish(
// 发送到那个交换机
"consumer.exchange",
// routingKye是那个
"key.send",
// 是否有特殊参数
null,
// 消息体
bytes
);
// 关闭连接
channel.close();
connection.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
3.准备一个消费者
3.1 在消费者这里我们声明了交换机 ,对列,并进行了绑定,以及对对列的监听
package com.consumer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.po.UserPo;
import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.User;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 消费者 监听消息
* @Author sj
* @Date: 2022/04/18/ 11:13
* @Description
*/
@Service
@Slf4j
public class Consumer {
/**
*序列化类
*/
private ObjectMapper objectMapper = new ObjectMapper();
/**
* 异步线程
* 声明消息对列、交换机、绑定消息的处理
* 监听对列
*/
@Async
public void handleMessage() throws IOException, TimeoutException, InterruptedException {
// 创建工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
// 设置端口
connectionFactory.setHost("localhost");
// 创建于broker的Tcp连接
try(Connection connection = connectionFactory.newConnection()){
// 创建信道
Channel channel = connection.createChannel();
// 创建交换机
channel.exchangeDeclare(
// 交换机名字
"consumer.exchange",
// 交换机类型
BuiltinExchangeType.DIRECT,
// 数据是否持久化
true,
// 不用了是否删除
false,
// 是否需要特殊参数
null
);
channel.queueDeclare(
// 对列名
"key.consumer",
// 数据持久化
true,
// 是否独占吃列
false,
// 不用了是否删除
false,
// 是否需要特殊参数
null
);
// 对列和交换机进行绑定
channel.queueBind(
"key.consumer",
"consumer.exchange",
"key.send"
);
// 监听对列
channel.basicConsume(
// 监听那个对列
"key.consumer",
// 自动签收
true,
// 消息处理
deliverCallback,
consumerTag -> {}
);
while (true){
Thread.sleep(1000000);
}
}
}
/**
* 接收消息的处理
*/
DeliverCallback deliverCallback = (consumerTag, message) -> {
System.out.println("n1");
log.info("consumerTag是:{}",consumerTag);
// 转成String
String messageBody=new String(message.getBody());
// 序列化成对象
UserPo user = objectMapper.readValue(messageBody, UserPo.class);
// 然后接下来就对对象进行操作,我这里就打印一下就好了
log.info("接收到的对象是:{}",user);
};
}
4.声明异步类
4.1 这里声明异步类,是为什么了消费端的交换机、对列的创建使用
package com.config;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
/**
* 对MQ进行异步处理的异步类
* @Author sj
* @Date: 2022/04/18/ 11:40
* @Description
*/
@Configuration
@EnableAsync
public class AsyncTaskConfig implements AsyncConfigurer {
/**
* 在里面准备一个线程池 避免溢出,真实环境会存在此类问题,所以小编在这里准备了
* @return
*/
@Override
@Bean
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
// 核心线程数
threadPoolTaskExecutor.setCorePoolSize(10);
threadPoolTaskExecutor.setMaxPoolSize(100);
// 缓冲对列长度
threadPoolTaskExecutor.setQueueCapacity(10);
// 所有线程结束才关闭
threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
threadPoolTaskExecutor.setAwaitTerminationSeconds(10);
threadPoolTaskExecutor.setThreadNamePrefix("Rabbit-Async");
// 初始化线程池
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
5.声明RabbitMQ的配置类
5.1MQ的配置类主要是用于对消费者handleMessage()方法的异步调用,使得项目启动时,就帮我们把交换机和对列进行创建
package com.config;
import com.consumer.Consumer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* MQ配置类
* @Author sj
* @Date: 2022/04/18/ 11:43
* @Description
*/
@Configuration
public class RabbitMqConfig {
@Autowired
private Consumer consumer;
/**
* 调休方法实现异步
*/
@Autowired
public void startListenMessage() throws TimeoutException, IOException, InterruptedException {
consumer.handleMessage();
}
}
到此我们在java中使用RabbitMQ完整代码都已写好,我们测试跑一波看看效果
总结:本篇我们学会了如何使用RabbitMQ实现简单的消息发送和接收处理。
流程: 1.发送端
1.生产者和Broker建立TCP连接,
2.生产者和Broker建立通道。
3.生产者通过通道消息发送给Broker,由Exchange将消息进行转发
4.Exchange将消息转发到指定的Queue(队列)
2.消费端
1.消费者和Broker建立TCP连接
2.消费者和Broker建立通道
3.当有消息到达Queue时Broker默认将消息推送给消费者
4.消费者接收到消息进行处理
问题:1.我们发送的消息真的发送出去了吗?
2.消息真的被路由了吗?
3.当消息过多的时候,消费端能消费过来吗?
4.消费端出现异常怎么办?
5.对列爆满怎么办?
6.如何转移过期的消息?
以上这些问题还等待我们去解决,下一章讲一一给大家,来自本人的学习笔记,觉得不错的三连哦!爱你们