Spring Boot 项目学习内容详解(一)

在消息队列中,存在一些比较核心的概念

1.交换机 exchange

2.队列 queue

3.绑定 binding

4.消息 message

这些都是存在于 BrokerServer 中的

会在项目的目录中创建 上述四个类

交换机类中的代码

java 复制代码
@Data
public class Exchange {
    //此处使用 name 来作为交换机的身份的唯一标识
    private String name;
    //交换机类型:直接交换机(DIRECT)、主题交换机(TOPIC)、扇出交换机(FANOUT)
    private ExchangeType type = ExchangeType.DIRECT;
    //durable 表示该交换机是否需要持久化存储,true 表示需要持久化存储(由硬盘决定),false 表示不需要持久化存储
    private boolean durable = false;
    //如果当前的交换机,没人使用,就会自动删除,true 表示如果当前的交换机没人使用,就会自动删除,false 表示不会自动删除
    //这个属性先放在这里,后续代码中并没有真正的去实现这个功能,但是在RabbitMQ中是有实现的(属于锦上添花,可有可无)
    private boolean autoDelete = false;
    //arguments(参数/选项) 表示创建交换机是指定的一些额外的参数选项,在这个项目中是并没有实现的,但是在RabbitMQ中是有实现的
    //为了把这个 arguments 存储在数据库中,就需要把 Map 转成 json 格式的字符串
    private Map<String, Object> arguments = new HashMap<>();
}

1.使用 name 作为交换机中的唯一标识的原因是,本次的消息队列主要是通过去模仿RabbitMQ来进行创作的,在RabbitMQ中的交换机就是通过 String name 作为交换机的唯一标识

2.这这个项目中使用到的交换机主要是有三种分别是:直接交换机(DIRECT),主题交换机(TOPIC),扇出交换机(FANOUT),在这里我们使用枚举的方式通过 数字 0, 1, 2 来分别代表着三种交换机

3.这里里的 durable 是用来表示是否需要进行持久化存储的

4.autoDelete 是用来表示 如果当前交换机没有人使用的话,就会自动删除,这里的"人"指的是客户端的调用方

5.arguments 是用来在创建交换机的时候可能会指定一些额外的参数选项,在后续通过sqlite进行建表操作的时候,还需要把 arguments 转成 json 格式的字符串用来进行存储

交换机枚举类

java 复制代码
/**
 * 通过枚举的方式来表示三种交换机的类型
 */

public enum ExchangeType {
    DIRECT(0),
    FANOUT(1),
    TOPIC(2);

    private final int type;

    private ExchangeType(int type) {
        this.type = type;
    }

    public int getType() {
        return type;
    }
}

1.创建了 getType 是用来获取当前交换机的类型的

队列类

java 复制代码
/**
 * 这个类一个存储消息的队列
 * MSG => Message
 */
@Data
public class MSGQueue {
    //表示队列的身份标识
    private String name;
    //表示队列是否需要持久化存储,true表示需要持久化存储,false表示不需要持久化存储
    private boolean durable = false;
    //这个队列是否是排他性的,true表示是排他性(表示这个队列能否别别的消费者使用)的,false表示不是排他性的
    //这个 独占 的功能展示 暂不实现
    private boolean exclusive = false;
    //这个队列是否是自动删除的,true表示是自动删除的,false表示不是自动删除的,没有人使用自动删除(这里的人表示的是消费者)
    //暂不实现
    private boolean autoDelete = false;
    //这个队列的参数选项, 暂不实现
    private Map<String, Object> arguments = new HashMap<>();

}

1.这里也同样是使用 name 作为身份的唯一标识,是为了符合 RabbitMQ 的格式

2.durable 和上述的意义是一样的

3.exclusive 表示的是排他性,表示这个队列是否可以别别的消费者使用

4.autoDelete 表示的也是自动删除

5.arguments 表示的是关于队列中的参数选项,在建表的时候也是需要转成 json 字符串用来存储的

绑定类(Binding)

java 复制代码
/**
 * 表示队列和交换机之间的关联关系
 */
@Data
public class Binding {
    private String exchangeName;
    private String queueName;
    //bindingKey 就是在出题,用来匹配使用的
    private String bindingKey;
    // Binding 这个东西,依附于 Exchange 和 Queue 的
    //比如,对于持久化来说, 如果 Exchange 和 Queue 任何一个没有持久化
    //你的 Binding 持久化是没有意义的
}

1.绑定类的主要作用就是为了匹配队列和交换机,所以这里需要创建 ExchangeName 和 queueName

2.bindingKey 是用来匹配交换机和队列的"密语"=>交换机:土豆土豆我是地雷 ,队列:地雷地雷我的土豆 => 匹配成功

3.在这个类中是不需要单独创建durable来判读是否需要进行持久话存储的,binding的持久化存储是取决于 queue 和 Exchange 是否都进行了持久化存储,如果都进行了持久化存储binding就自然进行了持久化存储,反之有一方没有进行持久化存储,binding自然也就不会进行持久化存储

消息类

java 复制代码
/**
 * 表示一个要传输的消息
 * 一个 Message 是包含两个部分
 * 1.属性部分 BasicProperties
 * 2.正文部分 byte[](正文是支持二进制数据的)
 * 这里的 Message 是需要在网络中传输的,并且也需要写入到文件去的
 * 此时我们就需要对 Message 进行序列化和反序列化
 * 此处使用 标准库中自带的序列化和反序列化
 */
@Data
public class Message implements Serializable {
    //这两个属性数 message 最核心的属性
    private BasicProperties basicProperties = new BasicProperties();
    private byte[] body;

    //下面的属性是辅助用的属性
    //Message 后续会存储到文件中(如果持久化的话)
    //一个文件中会存储很多的消息,如何找到某个消息,在文件中的具体位置呢?
    //使用下面的两个偏移量来进行表示 [offsetBeg, offsetEnd)
    //这两个属性是不需要被序列化保存到文件中的,此时消息一旦被写入文件之后,所在的位置就固定了,并不需要单独存储
    //这两个属性存在的目的,主要是为了让内存中的 Message 对象,能够快速找到对应的硬盘中的 Message 的位置
    private transient long offsetBeg = 0; //消息数据的开头距离文件的开头的位置偏移量(字节)
    private transient long offsetEnd = 0; //消息数据的结尾距离文件的开头的位置偏移量(字节)

    //使用这个属性表示该消息在文件中是否是有效的信息,(针对文件中的消息,如果删除,使用逻辑删除的方式(标记删除))
    //0x1 表示有效,0x0 表示无效
    private byte isValid = 0x1;

    //创建一个工厂方法,让工厂方法自动的帮我们封装创建 Message 对象的过程
    //这个方法中创建的 Message 对象,会自动生成唯一的 MessageId
    public static Message createMessageWithId(String routingKey, BasicProperties basicProperties, byte[] body) {
        Message message = new Message();
        if(basicProperties != null) {
            message.setBasicProperties(basicProperties);
        }
        message.setRoutingKey(routingKey);
        //此处生成的 MessageId 以 M- 为前缀方便区分
        message.setMessageId("M-" + UUID.randomUUID());
        message.body = body;
        //此处是把 body 和 basicProperties 先设置出来,这两个是 Message 中的核心内容
        //而 offsetBeg, offsetEnd, isValid 则是消息持久化的时候才会用到,再把消息写入到文档之前在进行设定
        //此处只是在内存中创建一个 Message 对象
        return message;
    }


    public String getMessageId() {
        return basicProperties.getMessageId();
    }

    public void setMessageId(String messageId) {
        basicProperties.setMessageId(messageId);
    }

    public String getRoutingKey() {
        return basicProperties.getRoutingKey();
    }

    public void setRoutingKey(String routingKey) {
        basicProperties.setRoutingKey(routingKey);
    }

    public int getDeliveryMode() {
        return basicProperties.getDeliverMode();
    }

    public void setDeliveryMode(int mode) {
        basicProperties.setDeliverMode(mode);
    }
}

1.在消息这个类中主要是分成两个核心部分 basicProperties 和 body 前者中存放的是关于 消息的一些属性,后者这是存放消息的内容部分

BasicProperties 类

java 复制代码
@Data
public class BasicProperties implements Serializable {
    //消息的唯一身份标识,此处为了保证 id 的唯一性,使用 UUID 来作为 Message 的id
    //UUID 是编程语言中生成唯一标识的一组方法
    private String messageId;
    //是一个消息上带有的内容,和 bindingKey 做匹配
    //如果当前的交换机类型是 DIRECT,此时的 routingKey 就是表示要转发的队列的列名
    //如果当前的交换机类型是 FANOUT,此时的 routingKey 无意义
    //如果当前的交换机类型是 TOPIC,此时 routingKey 就要和 bindingKey做匹配,符合要求的才能转发给对应的队列
    private String routingKey;

    //这个属性标识消息的持久化模式,1表示持久化,2表示不持久化
    private int deliverMode = 1;
}

1.这里的routingKey 就是和做匹配用的

本次消息队列中使用到的数据库选择的是sqlite,这个数据库相比于MySQL更加的轻量化,更适合这个项目

通过 MetaMapper.xml来对sqlite进行自动化建表操作

java 复制代码
/**
 * 元数据,元属性
 */
@Mapper
public interface MetaMapper {
    //提供三个建表方法
    void createExchangeTable();
    void createQueueTable();
    void createBindingTable();
}

1,上述是要创建的三张表

java 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zcfe.mq.mqserver.mapper.MetaMapper">
    <update id="createExchangeTable">
        create table if not exists exchange (
            name varchar(50) primary key,
            type int,
            durable boolean,
            autoDelete boolean,
            arguments varchar(1024)
        );
    </update>

    <update id="createQueueTable">
        create table if not exists queue (
            name varchar(50) primary key,
            durable boolean,
            exclusive boolean,
            autoDelete boolean,
            arguments varchar(1024)
        );
    </update>

    <update id="createBindingTable">
        create table if not exists binding (
            exchangeName varchar(50),
            queueName varchar(50),
            bindingKey varchar(256)
        );
    </update>
</mapper>

这里通过自动换进行创建三张表,需要值得注意的就是 arguments 在这里是通过字符串的格式来进行存储的,所以对于源代码中的Map就要进行序列化操作转成json字符串

相关推荐
哪里不会点哪里.2 小时前
Spring Boot 启动原理深度解析
java·spring boot·后端
Hx_Ma162 小时前
SpringBoot配置文件占位符
java·spring boot·后端
●VON2 小时前
Flutter for OpenHarmony:基于三层 Tab 架构与数据模型解耦的 TodoList 产品化演进
学习·flutter·架构·openharmony·布局·技术
机器学习之心2 小时前
集群中继无人机应急通信双层多目标协同优化部署:融合无监督学习与凸优化及启发式算法的MATLAB代码
学习·无人机·启发式算法·双层多目标协同优化
韩立学长2 小时前
【开题答辩实录分享】以《在线预问诊系统设计与实现》为例进行选题答辩实录分享
vue.js·spring boot·mysql
Loo国昌2 小时前
【LangChain1.0】第十四阶段:Agent最佳设计模式与生产实践
人工智能·后端·算法·语言模型·架构
@––––––2 小时前
论文学习笔记:FAST - 高效的视觉-语言-动作模型动作分词技术
笔记·学习
Gain_chance2 小时前
22-学习笔记尚硅谷数仓搭建-日志表建表语句解析、数据装载及脚本装载数据
数据仓库·笔记·学习
知识分享小能手2 小时前
Oracle 19c入门学习教程,从入门到精通,Oracle数据库控制 —— 事务与并发控制详解(14)
数据库·学习·oracle