技术栈学习

Spring Cache 整合 Redis

  • 序列化器配置:参考https://www.jb51.net/database/3236472ch.htm
    为什么需要使用其他序列化器呢?默认的 jdk 序列化器会将对象压缩成二进制流 虽然效率高且空间少 但是可读性很差 如果需要肉眼查看数据 就会很难受 因此采用 string 和 json 序列化器 至于泛型 json 序列化会额外记录数据类型 反序列化时可以组装正确的对象类型 详见链接
  • 缓存命名空间:就是在缓存的键添加一个前缀 用于区分不同对象类型或服务
  • 非锁定的缓存写入器:应该是为了写的高并发
  • cachable 注解的使用:value 是缓存的命名空间 key 则是后缀 这两个参数生成一个缓存键 缓存值则是返回对象的序列化结果
  • 什么是旁路缓存 以及为什么要使用这种模式:https://zhuanlan.zhihu.com/p/369916208 总结就是 使用注解就完事了
  • 鉴权和缓存:个人理解 鉴权必须要在缓存之前进行 否则一是不安全 二是无法区分用户信息 因此要不就在 repo 层缓存 要不就把鉴权提取到控制层(有点违反业界常规 不过实践才是真知) 然后在业务层做缓存
  • 实际生产时发现 基于注解进行缓存 基本上只能针对每一个方法进行缓存 也就是一种方法对应一个缓存键 这导致如果业务比较复杂 会有多种缓存键 在增删改的方法上需要驱逐所有缓存键 而且由于注解无法进行模糊匹配 有些范围型的参数更是无法作为缓存键 因此缓存还是用于比较简单(getById)或者是比较重要的几个方法即可 而且因为不用 id 做缓存键 在业务层需要进行拆分 才能使用对象的其他属性作为参数

分布式服务的认证

  • 首先 分布式系统下的认证按照认证的处理者分为两种(不严谨)

    • 集中式认证:当前更常见采用的认证方式 把认证服务(登录鉴权)交给某一个服务进行
    • 分散式认证:每个服务都可以进行认证
  • 不管是哪种认证 都需要统一管理 session 或 token 否则做不到单点登录(一次登录所有服务)

  • 我个人采用过把所有的 session 管理都交给一个服务器来进行 然后转发请求给其他服务的架构 显然这样的架构是不合理的 违反了分布式的初心 所以不管是哪种认证 都应该在每个服务器进行各自的 session 查询

  • 目前认为最优的架构:LB 服务器->各种应用服务器(服务器内部使用 security 来进行 session 的校验 但是登录请求只在 user 服务进行处理)

  • 基于 session 和 token 又可以分为不同的技术方案

    • Spring Boot 框架下可以使用 Spring Session 这是 spring 提供的最完美的 session 共享方案 会将 session 存储到 redis 中
      青空提到有一个问题 即一个服务调用其他服务时会因为没有 cookie 而被 401 我认为有两个方案:
      1. 像之前的旧架构一样 采用某一个服务器集中进行认证转发(这不好)
      2. 自定义一个拦截器 放行所有服务器内的请求 要求认证所有服务器外的请求 可以通过 allowed_ips 或者 header 中添加 authorization 来实现 这种方案解决不了所有的 api 都对于已登录用户暴露的问题 只有重复验证 session 才能解决
      3. 重复验证 session 自定义 openfeign 的拦截器 把 session 带上
    • OAuth2 使用推荐的授权码模式 一方面登录会重定向到第三方验证服务器 保证密码不泄露给客户端 另一方面会使用授权码和 secret(一个只有应用服务器和验证服务器协商好的密钥)来获取 token 保证 token 不泄露 (原理其实不是很懂 流程大概就是这样)
      配置 OAuth2 后即可向对应 url 发送请求来获取 token 还有种 refresh 模式 可以刷新新的 token
      使用 JWT 标准 令牌内会包含用户信息 省去查询 及三部分 标头 载荷和签名 header 和 payload 存储了一些信息 比如加密算法 用户信息 使用了 base64 编码(非加密) 签名则是 header 加 payload 进行加密后的结果 只有服务器可以解析 资源服务器相当于各个 service 的配置 yml 验证服务器则是配置 OAuth 和 Security

Spring Cloud

  • LoadBalancer:springcloud 自己的实现 使用服务拦截器拦截不同功能的微服务之间的通信 选择要用的服务器实例 策略可以是随机 也可以是轮询(RoundRobin 默认策略) 策略可以自定义 Config 类注入来配置

    • 可以使用 OpenFeign 实现负载均衡 在需要注册的服务接口(client 类)上使用注解 有点像声明了一个 repo 接口 注入到服务类里使用 比如单服务的 repo 是向数据库里自动获取数据变成实体 这个 client 就是向其他服务自动的获取了数据 实际上就是把 http 通信和选择实例的过程一起封装成了接口
  • Hystrix:服务熔断功能 即多个服务调用的级联 可能发生雪崩效应(最后一个服务停止了 前面的所有服务都没有必要调用)服务降级是调用较差的保底操作来保证响应正常 服务熔断则是直接熔断 快速返回异常信息 比如你一直调用某个服务 会降级执行补救措施 等你不调用了后 又恢复正常调用 返回异常
    使用 OpenFeign 也可以实现 基于注解注入 fallback 类即可
    监控页面:配置好后进入对应的 url 即可管理

  • Gateway:官方推荐的网关 可以把不同端口的服务统一到一个端口 根据断言规则进行转发给对应的 controller 客户端进行发送请求就无需分类 只需和单服务一样用名字分开即可

  • 配置中心 Config:管理所有配置文件 从 git 云端仓库里获取配置文件取给各个服务

  • Nacos:Alibaba 的服务注册器 可以设置非临时实例(如果断开显示下线) 可以设置分区 并设置同分区选取策略 可以设置配置中心 监听配置文件 如果配置改变 会输出改变内容等 设置命名空间 不同空间的服务实例无法交流 可以分组 但是不知道有什么用 集群模式 需要分别运行多个 nacos 连接同一个数据库 最后配置 nginx 代理作为 SLB 负载均衡服务器

  • Sentinel:流量监控工具 可以进行流量控制 防止过快的请求 对于超出阈值的限流进行丢弃 也可以使用注解针对某一个方法进行限流 这样就可以超出阈值时处理抛出的异常 可以设置链路 即只当某个入口资源进行调用此接口时才限流 还可以自定义异常处理返回页面 可以自定义某一个热点参数进行限流 也可以设置各种服务熔断规则

  • Seata:解决分布式事务 实现全局事务

  • Redis:

    • 分布式锁 防止超借问题 使用 setnx 作为锁(只有 key 不存在时才能 set) 为了防止死锁 设置时间阈值 超时自动释放(delete a)当然超时设置也存在很多问题(我没理解) 可以使用 redis 提供的现成框架进行处理(也就是在 java 里加锁)
    • MySQL 与分布式 同上 也可以使用主从复制以及分库分表(使用 sharding JDBC)
  • Sharding JDBC:一个中间件 用于和分片的数据库进行交互 适用于 JPA 以及关系型数据库
    通过在 yml 文件里编写配置来实现不同的分库分表策略 有用 可能可以用于微服务架构下不同业务分库
    分表 逻辑表分为多个物理表 基本逻辑都是进行配置哈希映射到不同的物理表 如果是范围查询会进行 union 全表查询
    分布式序列算法 目的是产生全局唯一索引

    1. UUID 快速生成无序的 32 位 id
    2. 雪花算法 时间戳+工作机器 ID+序列号
      读写分离 也是使用主从节点来实现
  • RabbitMQ:消息队列 基于生产者消费者的通信机制 生产者发送消息(一次业务操作)后即可继续工作 无需等待 实现了解耦的异步通信 交换机相当于路由器 根据 routing key 把消息分配到不同的队列中

    1. hello world 模式 一个生产者一个消费者
    2. 工作队列模式 一个生产者多个消费者
    3. 发布订阅模式 生产者发布一条消息 分发到多个队列里
    4. 路由模式 交换机通过 routingkey 分配给固定的消息队列
    5. 主题模式 将 routingkey 用模糊匹配的方式进行转发
    • 死信队列 使用一个交换机和队列作为死信处理用 由对应的消费者进行处理 死信有三种情况 被拒绝 超时(TTL)或者是消息队列达到最大长度满了 会把最久的消息出队
    • 集群模式
  • Spring Cloud Stream:消息队列的中间件 封装了整个消息队列 只暴露 input 和 output 的接口

  • Spring Cloud Bus:相当于消息总线 可以广播通知其他服务

Nginx

Nginx (engine x) 是一个高性能的 HTTP 和反向代理 web 服务器软件 可以进行反向代理和负载均衡等功能

  • 安装

    • 包管理安装:比如 Linux 的 apt
    • 编译安装: 因为是 C 语言开发的 所以可以进行编译来进行安装 如果需要自定义特殊功能就使用这种
    • 容器安装:docker 拉取官方镜像即可
  • 进程模型

    • master 主进程
    • worker 工作进程 数量与 CPU 内核数保持一致比较好
  • 配置文件

    • nginx -t命令检查配置文件是否正确

    • nginx -s reload命令重新加载配置文件

    • 配置块分为 3 个

      1. 全局配置
      • user 指定启动进程的用户
      • error_log 指定日志输出路径
      • pid 记录 pid 的文件路径
      • worker_processes 设置工作进程数量 auto 根据 CPU 核数设置
      1. events 块 配置一些服务器客户端网络连接参数
      • worker_connections 一个工作进程的最大客户端连接数
      1. http 块
      • include 指令可以包含其他配置文件(为了拆分)或者 mime.types(用于处理不同后缀的文件)

      • default_type 默认返回文件类型

      • sendfile 开启 sendfile

      • keepalive_timeout 连接超时时间

      • upstream 块 指定一组服务器的池 来实现负载均衡

        • server 指定 url
        • weight 指定权重
      • server 块

        • listen 监听端口
        • server_name 虚拟主机名 如果请求的 host 名和此名匹配 则处理请求
        • default_type 默认响应类型
        • root 指定默认根目录
        • location 块
          • 具有四个匹配优先级(从低到高) 同优先级下 匹配更精确的优先
          1. 前缀匹配(/) 相当于把前缀更换为 root 路径来查找文件资源
          2. 正则匹配(*)带*的是不区分大小写
          3. 优先前缀(^~)
          4. 精确匹配(=) 路径必须完全一致 最强
          • proxy_pass 反向代理转发给其他端口 也可以转发给 http://upstream_name 来实现负载均衡
          • root 指定根目录 提供静态资源 覆盖默认配置
          • index 指定查找哪些静态文件作为首页
          • rewrite 重写请求的 uri 进行重定向
          • return 直接返回状态码和消息
          • deny/allow 依据 ip 地址进行访问限制
          • add_header 为响应添加 header 键值对形式
          • try_files 按照顺序查找文件 定向到第一个匹配的文件 这对于 SPA 应用(比如 react)非常重要 因为 SPA 项目是单页面的 不能直接映射文件路径 都需要转发给 index 文件来处理

Docker

  • 为了解决不同环境不同操作系统导致的程序运行问题 把用户空间 环境以及程序(不包含操作系统和内核)全部打包成一个文件(镜像) 有需要使用的用户只需要拉取镜像来解压缩后运行在容器(一个相对隔离 共享了主机操作系统的内核 但是运行在独立的用户空间的进程) 总结一下就是不带操作系统内核的 专门用于运行某一个程序及其所需依赖和环境的轻量虚拟机

  • 基本指令

    • pull 拉取仓库的某个镜像到本地 冒号+版本可以拉取特定的镜像
    • images 列出本地的镜像
    • run 运行本地镜像 –name 指定容器名称 –rm 容器停止后立即 rm -it 参数让 base 容器可以持续运行 -d 后台运行 -p 指定端口映射 –network 指定网络模式 -m 指定内存限制 –memory-swap 指定总内存限制 默认无限制 -c 分配 CPU 权重 默认 1024 –cpuset-cpus 指定使用哪个 CPU 核(0base) –cpus 指定使用几个核 –device-read/write 指定 IO 读写的限制速率 bps 指定数据量 iops 指定 io 次数 –restart 指定容器是否自动重启
    • ps 查看所有运行的容器 -a 打印所有容器 包括已终止的
    • start/stop/restart 启动停止重启
    • rm 删除非运行状态的容器
    • commit 把运行的容器打包为新的镜像
    • build 根据当前目录下的 dockerfile 进行构建镜像
    • cp 把宿主机的文件复制进容器 或者反过来
    • logs 输出日志信息
    • exec 可以执行容器内的指令 比如 bash
    • kill 强制终止
    • pause/unpause 暂停容器运行
    • stats 监控容器运行状态
    • top 监控某一个容器
  • 镜像

    • base 镜像 即基本的操作环境 如 centos 前面就说过 容器会使用主机的内核 因此 base 镜像实际上只有用户文件 非常小
      • 使用 uname -r 命令查看当前主机内核版本
      • 其他镜像是安装在 base 镜像之上的 这样可以共享 base 镜像
      • 最上层是一个可写容器层 用于修改 不影响下层的镜像
      • 因此读取文件 是从上往下查找 创建修改文件则是从上往下修改 在最顶层创建 删除则是从上往下查找 进行删除标记
    • 构建镜像
      • 第一种方法是使用 commit 但是不推荐 因为不能显式展示镜像经过什么变化 而且比较麻烦
      • 第二中方法是使用 dockerfile 相当于写一个指令集文件
    • 发布镜像
      • 和 github 类似 去 dockerhub 创建一个 repo 然后进行发布 就可以 push 到云端
    • 使用 IDEA 打包 springboot 为镜像
      • 首先编写 dockerfile 需要选取一个 base 镜像 并安装 java 环境
      • 使用 IDEA 和服务器上的 docker 进行连接 需要开放的端口 连接后即可在 IDEA 上进行容器的构建
      • 把 springboot 项目打包为 jar 包 使用 COPY 命令把 jar 包复制进镜像
      • 使用 CMD 命令运行 jar 包 使用 EXPOSE 命令暴露端口给外部 也就是端口映射
      • IDEA 也可以作为 GUI 的客户端来操作 docker 服务器 比如上述的构建和发布镜像
  • 容器网络

    • network ls 指令可以列出网络类型
      • none 是回环网络 即只有本地 没有任何网络连接
      • bridge 是桥接网络 是默认类型 即 docker0 作为桥 连接了每一个容器 内网 ip 为 172 网段
      • host 是宿主网络 即和宿主机共享网络
    • 自定义网络驱动
      • 计网没学 听不太懂
    • 容器间通信
      • 可以直接 ping 172 的网段
      • 可以使用 docker 提供的 dns 服务器 为容器指定名字 然后 ping 名字即可访问
      • 也可以指定两个容器共享一个内网 ip 地址
    • 容器的外部通信
      • NAT 网络地址转换 即内网和外网 ip 的映射
      • docker 所处的局域网也需要一个虚拟 NAT 起到路由器的作用 来与外界通信
      • 配置端口映射 使得外界可以与容器内部某一个端口进行通信
  • 容器的持久化存储

    • 通过指定-v 参数 来进行挂载 相当于一个映射 如果不指定挂载 docker 会自动管理一个位置进行挂载
  • 容器间的数据共享

    • 使用 volume 指令管理数据卷 把不同容器的数据卷挂载到宿主机的一个公共目录即可
    • 使用–volumes-from 来跟随挂载
    • 也可以把数据完全放入容器 由 docker 自动替我们管理挂载点 而自动管理会先把数据卷里的文件都复制到挂载点后再进行修改 这样如果需要移植到别的主机时 就不用再复制数据了 而是数据卷容器自动复制到了新的主机挂载点 比如所有前端资源放入一个容器 再建立端口映射 就可以通过宿主机端口直接访问前端页面
  • 容器编排 Docker Compose

    • 实现多容器集群的一键部署 作用类似于服务器上的 script 脚本 当需要进行服务器上多个服务的部署时可以进行集成
    • 先编写 yml 配置文件 指定好需要创建的容器名称和镜像源以及端口映射
    • 可以使用 IDEA 的图形化界面操作 也可以 linux 指令操作
    • 完整的部署流程中 如 MySQL 的数据库密码配置等需要手动配置 也可以在 compose 的 yml 文件里配置 详见 https://www.bilibili.com/video/BV1r34y1p7j9/?p=20&spm_id_from=pageDriver&vd_source=afe773a10ce28a886979173e5e8bfc2d 视频最后一 P
    • 适用于单主机 多主机详见 k8s

Kubernetes

  • 容器编排引擎 用于管理多主机的多容器 主要特性有
  1. 可以使用 yml 配置文件简单的进行容器编排
  2. 高可用性 提供自动重启 自动修复
  3. 高扩展性 可以根据负载变化动态的扩展收缩资源
  • 核心内容:
    • node 一个物理机或虚拟机
      • node 也叫 workernode 在架构中负责实际工作
      • node 包含 kublet kube-proxy 和 container-runtime
      • 容器进行时负责拉取镜像并进行运行
      • kublet 负责管理监控 pod
      • proxy 负责代理 启动负载均衡 结合 service 进行
    • master node 管理其他节点的 node
    • pod k8s 的最小调度单元 是一个或多个容器的组合
      • 一个 pod 一般只运行一个容器 有时为了引入管理辅助系统 会使用 sidecar 模式 把一些日志 监控容器和主容器放在一个 pod 里
      • pod 的 ip 会自动分配 在集群内部通信 node 外无法访问 并且是 ip 是动态的 当自动重启或修复时会改变
    • service 类似反向代理 一个负载均衡器中间层 自动连接合适的容器 ip
      • 分为内部和外部 内部服务只被服务内部访问
      • 服务可以映射到 node 端口号 暴露给外部
    • ingress 用于管理集群外部访问内部
    • configmap 用于管理配置信息 进行注入 相当于 jar 包的参数 无需重新编译 只需要重新运行 pod 明文存储 不建议存储敏感信息
    • secret 存储敏感信息 只进行 base64 编码
    • volume 实现持久化 把资源挂载到磁盘上
    • deployment 一个或多个 pod 组合 用于动态管理 pod
    • statefulset 用于部署数据库 pod 的 因为数据库是有状态的 需要额外的数据同步和共享
  • 架构:

Cloud Firestore

一个基于非关系型数据库的云端数据库服务 非关系型数据库适合读大于写的场景

  • 存储形式:文档(json 对象)和集合(数组)
  • 浅查询:查询一个文档时 不会查询其子集合 因此不需要的或者过于大的数据应该拆分 比如一本书的完整内容 应该拆分为 chapters 子集合
  • 查询性能:firestore 会为每一个文档的每一个属性(键值对)进行索引 使用二分查找加快查询 对于范围查询 firestore 仍采用索引的方法 对于多个等于查询 使用了 zip-zap 的合并方法一次查询出所有符合两个等于的数据 对于多个 field 的范围查询 采用组合索引 按优先级排列 比如 price_rating 字段
  • 数组不支持任何索引操作 但是支持查询包含特定元素的数组操作
  • 类似于书籍 评论的存储 有两种方式 一种是评论作为子集合 另一种是全部评论存储为一个集合 后者虽然看起来会导致查询性能变差 但是由于二分查找是对数级的 实际上的查询绝对时间不会增长多少 但是如果需要进行范围查询 就需要使用组合索引 设想要查询某一个书籍的按时间排序的评论 后者就需要使用组合索引”bookId_time” 而前者只需要在对应的文档里进行单索引查询即可 这两者的选择基于你的查询大部分是针对某一个书籍还是全部书籍
  • 安全问题 比如一个文章具有编辑权限 指定哪些用户可以进行修改 最简单的做法肯定是直接存储一个 uid 的数组 但是这样就泄露了 uid 可以使用 private 的文档来存储 (这点我们先不关心)
  • 分页
    • limit 函数简单的限制了查询数量(前 20 个)
    • 随后即可使用 start 函数进行某一个文档后的精确查询
    • 分页带来的数据延迟:比如我先获取了前二十个元素,然后第一个元素被其他人进行过修改,当我继续下拉滚动获取第二十一到第四十个元素时,只能保证新的二十个是最新的,而前二十个却是不一致的。 可以通过监听或者是每次下拉获取全部元素来解决 但是目前对我们的项目应该用处不大 因为我们不用分页 或者实时性不高
  • 事务
    • 在非关系型数据库中尤为重要 因为有很多很多冗余数据需要保持一致 修改时就需要事务
    • bached write(批量写) 一次性修改多个文档 用于修改某一个数据
    • transaction 和其他传统做法不同 并不是锁定需要修改的数据来保持原子性 而是监测是否有其他修改数据 如果数据被修改了 重新读取数据并开始事务 如果没有 则提交修改
    • firestore 提供了一个直接增减或减少数字型数据的功能 简单的修改可以使用这个 而无需事务 但复杂的操作(比如交易)仍需事务
    • 由于一次事务最多写入 500 个文档 并且云端的事务是基于传统策略(锁定)的 当进行大规模的数据库迁移或修改时 需要做权衡 选择更好的原子性(一次事务尽可能多写)还是更好的性能(一次事务尽可能少锁定文档)
  • 离线支持
    • firestore 的离线上传是后覆盖的 也就是说 顺序由连接到云端上传的时间决定 而不是实际在客户端里修改的时间
    • firestore 的离线支持是基于 LRU 缓存 我们的项目采用本地数据库存储 用不到本地离线支持
  • 实时数据库
    • 好像没什么用处
  • 无服务器计算(云函数)

Redis

  • 基本操作:键值型数据库 所以相当于 map 可以 set、get、del 也可以设置过期时间 或者设置为永久数据 keys 命令查看所有键
  • 哈希类型:hset 命令即可插入 map 类型的键值对
  • list 类型:lpush rpush 头尾插入元素
  • 集合类型:不允许重复 key 不支持随机访问 sadd 命令
  • 持久化:两种方式
    1. 保存所有数据到磁盘里(RDB) 可以手动保存(save) 也可以配置文件里设置自动保存 但是会存在自动保存触发前崩溃的情况
    2. 或者保存所有命令(AOF 和 mysql 一样) 每次操作都触发写入日志 更方便 缺点是每次启动 redis 都需要重新执行所有命令 有一个重写机制 可以把冗余的指令压缩 比如两条 set 可以合并为一条
  • 事务:输入 multi 命令开启事务模式 后续输入的指令会保存到事务队列中 输入 exec 命令将所有事务队列中的指令执行
  • 锁:不同于 mysql redis 的锁是乐观锁 悲观锁即占用资源的进程会禁止一切其他访问操作 乐观锁即操作前检查一下是否有其他进程进行操作 如果有就先放弃 否则进行操作(有点像 CAS 锁)乐观锁有 ABA 问题 不过 redis 是基于版本号来检查是否被修改过的 所以没有
  • Jedis:redis 基于 java 的 api 函数基本和指令一模一样
  • springboot 整合 redis 数据库:通过注入 template 来使用各种 api 手动进行数据的 crud 就和 jpa 类似 配置了序列化器后 也可以存储对象 相当于存储 json 格式的字符串
  • 分布式
    • 主从复制:
      • 多台 redis 服务器 从节点只能读 读写分离 使用 replicaof 指令设置一台服务器为另一台的从节点
      • 主从节点都维护一个复制偏移量(相当于主节点向从节点复制了多少字节的数据) 用来判断主从节点是否数据同步
      • 这种结构显然主节点挂了后仍可以读 但是不能写 可以设置主节点挂了后自动配置某一个同步好的从节点为新的主节点 从而实现服务的可靠性 详见哨兵模式
      • 从节点也可以有从节点 个人理解这样可以做到每个节点(服务器)均等的分配性能 即同步给 n 台服务器的这个 n 是均等的
    • 哨兵模式:
      • 使用 sentinel monitor 指令进行配置哨兵
      • 哨兵会监控所有主从节点 一旦主节点挂了 并且持续一段时间后(防止网络波动影响) 选择一个从节点为新的主节点 顺便把挂掉的主节点变成新的从节点
      • 可以配置节点的优先级 来选择新的主节点
      • 哨兵同理也是不能挂的 所以也可以配置多个哨兵 还可以配置当 n 个哨兵认为主节点挂了后才进行重选
    • 集群搭建:
      • 当数据实在太多时 需要进行分库 因此可以实现多个主节点分别存储一部分数据 多个主节点作为哈希桶 根据键的哈希值来决定存放的节点是哪个 目的是分担单节点的内存压力

Redisearch

Apache Maven

  • 一个项目管理工具

  • pom 文件结构

    • groupId 组名称 即隶属哪个组织
    • artifactId 项目名称
    • version 版本号
    • type 依赖类型 默认 jar
    • scope 依赖作用域
      • compile 默认 编译测试运行都有效
      • provided 运行时无效 比如 lombok
      • runtime 编译时无效 比如
      • test 只有测试时有效 比如 JUnit
      • system 从本地导入 jar 包而非远程仓库
    • option 依赖是否可选
      • 比如 mybatis 会导入很多不同的日志依赖 而实际上我们使用只需要选其中一个框架即可
    • exclusions 排除传递性依赖
      • 排除此依赖的某个传递依赖 比如版本不兼容想要降版本 就可以排除新版本
    • modules 子模块
    • packaging 打包类型 默认为 jar 父模块为 pom 即声明自己是一个包管理模块 只会按顺序打包子模块
  • 依赖导入都比较熟悉了 就是在本地仓库.m2 和云端仓库进行下载

  • 依赖继承

    • 父模块 dependecies 中的依赖会被子模块继承
    • dependecyManagement 项定义子模块所有的依赖版本等配置 如果子模块使用了其中的依赖 就会继承配置 也就是依赖管理
  • 常用指令

    • clean 清除缓存 清理整个 target 文件夹
    • validate 验证项目的可用性
    • compile 编译为 class 文件
    • install 将当前项目安装到本地仓库 提供给其他项目使用
    • verify 按顺序执行默认的生命周期阶段
    • test 执行测试
    • package 打包 jar 包到 target 文件夹里 在 pom 里配置插件后 可以把项目的所有依赖都一起打包

Apache Avro

  • 文档参考:https://avro.apache.org/docs/
  • python 需要安装 avro 库 java 则通过 maven 导入 avro 依赖
  • 需要预先编写好数据的 schema 语法见文档 编写好后即可使用 avro 的序列化与反序列化方法进行数据的压缩与解压
  • python 中数据类型比较自由 使用 dict 类型即可操作 但是 java 的数据类型比较严格 avro 本身提供一个 record 类封装数据 但是我使用了 fastjson 库的 json 类型来操作数据 这就导致必须要编写一个转换函数进行转换 并且这个转换需要递归分类进行 一旦类型对应不上 序列化时就会报错

Swagger UI

https://zhuanlan.zhihu.com/p/703966719

Java 线程池

https://blog.csdn.net/m0_72156649/article/details/140460116


技术栈学习
https://nwdnys1.github.io/2024/09/07/WEB技术栈/
作者
nwdnysl
发布于
2024年9月7日
许可协议