RabbitMQ之入门篇(二)

前言在上一篇我们对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.如何转移过期的消息?   

以上这些问题还等待我们去解决,下一章讲一一给大家,来自本人的学习笔记,觉得不错的三连哦!爱你们

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值