揭秘基础框架:如何简化软件开发?

首先我们需要明确什么是 基础框架 以及 基础框架 能给我们带来怎样的便利从而方便开发者快速根据业务需求构建可实施的业务项目.

1.1 什么是基础框架

1.1.1 定义

框架(framework)是整个或部分系统的 可重用 设计,表现为一组抽象构件及构件实例间 交互 的方法,另一种定义为,框架是可被应用开发者定制的应用 骨架

框架是一个 可复用 的设计构件,通常以 构件库 的形式出现,但构架库只是框架的一个重要部分,框架的关键在于框架内对象间的的交互模式和控制流模式。

从定义可以得出, 框架是一种 可复用 构件, 以 构件库 的方式加入到业务代码中, 从而避免重复开发达到复用的目的. 每个公司都会或多或少根据自己公司业务封装内部的开发基础框架. 比如蚂蚁金服基于 Spring Boot 自研的 SOFA, 属于金融级别的微服务框架; Vert.x 基于 Netty 封装的基于事件的异步框架; Dubbo 是一个高性能的、基于 Java 的开源 RPC 框架等.

考虑到面向的领域,以及实现编码实现,我们可以将将框架至少分为三类:

  1. 基础类库: 包含多数项目所需要的类库, 开发人员将其作为一个类库使用,可以简化一些常用的算法逻辑;
  2. 基础框架: 该框架应该整合或者实现 J2EE 开发所需要的常用功能, 为各类项目开发提供基础支持;
  3. 平台框架: 针对于某种特定领域,实现特定领域所需要的常用功能;

1.2 为什么需要基础框架

软件系统随着业务的发展,变得越来越复杂,不同领域的业务所涉及到的知识、内容、问题非常非常多。如果每次都从头开发,那都是一个很漫长的事情,且并不一定能将它做好。团队协作开发时,没有了统一标准,大家各写各的,同样的重复的功能到处都是。由于没有统一调用规范,很难看懂别人写的代码,出现 Bug 或二次开发维护时,根本无从下手。

而一个成熟的基础框架,它是模板化的代码,它会帮我们实现很多基础性的功能,我们只需要专心的实现所需要的 业务逻辑 就可以了。而很多底层功能操作,就可以完完全全不用做太多的考虑,框架已帮我们实现了。这样的话,整个团队的开发效率可想而知。另外对于团队成员的变动,也不用太过担心,框架的代码规范让我们能轻松的看懂其他开发人员所写的代码。

1.2.1 代码模板化

基础框架能够确保 代码风格 的一致性,同一分层的不同类代码,都是大同小异的模板化结构,方便使用模板工具统一生成,减少大量重复代码的编写。在学习时通常只要理解某一层有代表性的一个类,就等于了解了同一层的其他大部分类结构和功能,容易上手。团队中不同的人员采用类同的调用风格进行编码,很大程度提高了代码的可读性,方便维护与管理。

1.2.2 可复用

基础框架能够确保层次清晰,不同开发人员开发时都会根据具体功能放到相同的位置,加上配合相应的开发文档,代码重用会非常高,想要调用什么功能直接进对应的位置去查找相关函数,而不是每个开发人员各自编写一套相同的方法。

1.2.3 高内聚(封装)

基础框架中的功能会实现高内聚,开发人员将各种需要的功能封装在不同的层中,给大家调用,而大家在调用时不需要清楚这些方法里面是如果实现的,只需要关注输出的结果是否是自己想要的就可以了。

1.2.4 规范

基础框架严格执行代码开发规范要求,做好命名、注释、架构分层、编码、文档编写等规范要求。因为基础框架是所有业务项目的基础, 要让开发者更加容易理解与掌握。

1.2.5 可扩展

基础框架具备可扩展性,当业务逻辑更加复杂、数量记录量爆增、并发量增大时,可能只需要调整基础框架即可满足大部分业务需求, 避免在多个项目中去调整.

1.2.6 可维护

基础框架通过必要的技术手段, 保证业务代码的可维护性, 比如通过强制的代码检查保证代码格式统一, 提高可维护性; 统一的常用功能或特性保证开发者使用统一的方式处理通用逻辑, 同样提高了代码或项目的可维护性.

1.2.7 协作开发

有了基础框架,我们才能组织大大小小的团队更好的进行协作开发,成熟的框架将大大减轻项目开发的难度,加快开发速度,降低开发费用,减轻维护难度。

1.2.8 通用性

同一行业或领域的框架,功能都是大同小异的,不用做太大的改动就可以应用到类似的项目中。在框架中,我们一般都会实现一些同质化的基础功能,比如权限管理、角色管理、菜单管理、日志管理、异常处理…… 或该行业中所要使用到的通用功能.

1.2.9 总结

总结起来, 使用基础框架的优点如下:

  1. 重用代码大大增加,软件生产效率和质量也得到了提高;
  2. 代码结构的规范化,降低程序员之间沟通以及日后维护的成本;
  3. 知识的积累,可以让那些经验丰富的人员去设计框架和领域构件,而不必限于低层编程;
  4. 软件设计人员要专注于对领域的了解,使需求分析更充分;
  5. 允许采用快速原型技术; 有利于在一个项目内多人协同工作;
  6. 大粒度的重用使得平均开发费用降低,开发速度加快,开发人员减少,维护费用降低,而参数化框架使得适应性、灵活性增强。

1.3 与基础开发平台的区别

基础框架是基础开发平台的 子集, 是属于基础开发平台的中层的通用研发框架, 基础框架与基础开发平台的关系如下:

difference.drawio.svg

常见的基础开发平台不仅仅只提供了 基础开发框架, 而是在此基础上提供了更多的服务治理, 服务监控等功能, 更具备完善的基础设施建设, 包括持续集成与部署, K8S 等. 这一套通常需要百人团队花费几年时间逐步完善, 且使用场景一般在 分布式微服务 的业务场景中.

综上数据, 目前搭建一个 基础开发平台 对我们来说暂时还没有必要, 当前阶段提供一个 基础框架 意义更大.

2. 基础框架架构

framework_1.0.0.svg

2.1 技术选型

技术选型一般按照以下几个原则:

  1. 需要看软件特性是否满足需求, 包括兼容性, 扩展性和使用到的技术栈;
  2. 根据目前自己或者团队的技术栈和技术能力,能否可以平滑的使用;
  3. 技术社区的活跃度, 包括:
    1. 是否有专人维护;
    2. 是否有完善的文档;
    3. 遇到的问题是否能够快速得到帮助并解决;
    4. 是否在业内部被广泛使用;

按照上面的原则, 所选主要技术栈整理如下:

20241229154732_SgCYXo9I.webp

框架 说明
JDK 8 开发者工具
Spring Boot 2.3.12 底层框架
Spring Cloud Alibaba 2.2.9 Spring Cloud 框架
Nacos 2.x 配置中心
xxl-job 分布式任务调配
Hutool 常用工具包
Kafka 业务消息队列
EMQ 物联设备消息队列
MySQL 8.x 数据库
Druid 1.2.15 JDBC 连接池、监控组件
MyBatis Plus 3.5.x MyBatis 增强工具包
Redis 6.x key-value 数据库
Knife4j 3.0.3 Swagger 增强 UI 实现
MapStruct 1.5.3.Final Java Bean 转换
Lombok 1.18.24 消除冗长的 Java 代码
JUnit 5.8.2 Java 单元测试框架

2.2 主要特性

  • 使用 Maven 对项目依赖管理做了大量优化,抽象出公司顶级 Maven 父模块,统一管理公司所有子项目;
  • 项目模块分工明确,遵循单一职责,模块之间使用最小依赖原则,完全不存在循环依赖问题,精确控制 Maven 依赖传递,尽量避免依赖冲突 (如果存在依赖冲突,我们也会在编译时给出告警);
  • 使用不同的父项目将业务项目和框架项目进行隔离,并且提供 starter 的开发模板,简化和规范 starter 组件开发;
  • 使用 Java Annotation Processor 自动生成 starter 组件的元数据文件,减少重复配置,降低出错的概率;
  • 使用 Maven Plugin 自动生成打包配置,通用启动脚本,减少重复性工作,忽略不需要的配置以提高编译速度;
  • 将 BOM 管理项目依赖以统一全部项目的依赖,减少依赖冲突,且分为 3 层进行单独管理;
  • 使用 ThinJar 代替 FatJar, 方便修改配置与 Jar 替换且具备更高的可定制化;
  • 严格遵循阿里巴巴开发规范,且对代码进行了强制检查;
  • 在 Spring 基础上封装多个工具类,减少第三方依赖进而减少部署包体积;
  • 基于 Spring Boot Starter 封装多个基础组件且组件之间完全隔离,基于 SPI 自动设置默认配置,减少重复的开发工作;
  • 封装了 Spring 的事件处理器,彻底解决在 Spring Cloud 环境下事件监听器被多次执行的问题;
  • 封装了通用启动器,且在应用的整个生命周期提供各种扩展点以执行自定义逻辑;
  • 封装了统一的日志组件,减少业务项目的日志配置,且允许自定义日志配置以满足业务上的日志需求;
  • 封装了 REST 组件且提供了全局异常处理,统一的返回结果,接口参数验证,错误信息国际化,多种入参注入方式等;
  • 集成了 Nacos 作为配置中心,且对 Nacos 进行二次开发和优化,以满足现有业务需求;
  • 集成了分布式任务调度,以可视化的方式更加方便的管理定时任务,且提供 API 接口直接添加定时任务;
  • 集成了比 Swagger 更加优化的 API 文档工具;
  • 集成了多级缓存框架,封装了更加友好的分布式锁实现;
  • 封装了 MapStruct 简化实体间互相转换;
  • 集成了 Mybatis-Plus 简化单表操作,封装了通用的分页查询,枚举自动转换等;
  • 封装了 Mybatis-Plus 代码自动生成;
  • 封装了单元测试组件,使用 Junit 5 作为底层框架,且封装了并发测试工具,支持 Mock 等;

2.3 主要组件

2.3.1 项目依赖管理

任何业务项目存在一个较大的问题就是 项目依赖管理, 如果稍不注意就会发生依赖冲突, 导致项目启动失败。 如果要修改依赖版本需要考虑到多个项目的依赖关系, 为了彻底解决这个问题, 公司级的项目依赖管理方案: 所有业务项目都需要以 atom-business-parent 为项目父依赖, 统一提供 版本号管理Maven 插件集成公共配置:

  1. 项目依赖管理:

    创建了一个顶层 Maven 项目, 用于规范所有业务项目的定义, 现在只需要简单依赖一个父项目, 就可以完全继承所有依赖的版本号, Maven 插件, 项目依赖上传地址等。 一是能够统一公司所有项目依赖的版本号, 以减少依赖冲突 ; 二是减少业务开发时繁琐且重复的项目配置代码, 以将重心方法需求开发上

    为方便管理与根据不同的项目特点细化功能, 并抽离通用配置, 将父级项目细分为了业务父项目技术组件父项目依赖管理父项目一键部署父项目, 业务方只需要关心 业务父项目, 在框架升级时, 只需要修改版本号即可。

  2. Maven 插件:

    提供了代码规范检查, 依赖冲突检查, 启动脚本自动生成, 项目一键部署等功能。

    一是让所有项目的代码风格保持一致, 有效减小因为格式不统一导致的代码冲突 ;

    二是通过一些自动化的方式生成不可或缺的文件, 避免手动创建 ;

    项目一键部署可提高服务部署效率, 减少人工部署的时间, 可从原来的 30 分减少到 1 分钟之内, 如果是多服务部署, 效果更加明显;

    为了方便其他业务组开发业务相关的 Maven 插件, 我们还提供插件模板, 能够快速开发一个项目级 Maven 插件.

  3. SPI 与 Spring Boot 文件生成

    通过简单的注解为业务开发中使用到的 SPI 技术和 Spring Boot 自动生成配置文件, 无需手动创建, 且对开发透明无感知。

2.3.2.1 包含模块
模块 介绍
atom-supreme 公司顶层项目, 用于规范所有后端服务的依赖, 提供常用的 Maven 插件
atom-builder 框架顶层依赖, 用于管理通用配置, 依赖版本与项目依赖关系
→ atom-project-builder atom-business-parent 与 atom-component-parent 父依赖, 抽离公共配置
→ atom-project-denpendencies 维护业务开发中常用的第三方依赖版本, 避免依赖冲突
→ atom-dependencies-parent 公司级的依赖父项目, 管理所有依赖型项目
→ atom-business-parent 业务项目父级依赖, 集成自有插件与第三方插件, 并提供通用的插件配置
→ atom-distribution-parent 一键部署型项目父级依赖, 可简化子项目的配置
→ atom-component-parent 技术组件父级依赖, 可将源码上传到 Maven 私服, 方便本地调试
atom-plugin Maven 插件项目
→ atom-assist-maven-plugin 框架开发辅助插件, 可根据项目类型禁用 / 启用插件, 生成项目配置等功能
→ atom-checkstyle-plugin-rule 代码格式检查插件
→ atom-enforcer-plugin-rule 项目依赖检查插件
→ atom-makeself-maven-plugin 项目启动脚本优化插件, 可在 atom-script-maven-plugin 的基础上生成可直接运行的部署包
→ atom-plugin-common 插件项目基础模块, 提供开发插件的工具包
→ atom-pmd-plugin-rule 代码质量检查插件
→ atom-publish-maven-plugin 一键部署插件
→ atom-script-maven-plugin 启动脚本生成插件, 可根据参数生成项目特定的启动脚本
atom-starter-processor SPI 与 Spring Boot 项目相关的配置生成组件

2.3.3 开发工具包

我们封装了大量的常用工具包, 目标是使用一个工具方法代替一段复杂代码,从而最大限度的避免 “复制粘贴” 代码的问题, 彻底改变我们写代码的方式, 目的是为了减少代码搜索成本, 避免网络上参差不齐的代码出现导致的 BUG 。

2.3.3.1 包含模块
模块 介绍
atom-center-autoconfigure 自动装配基础依赖
atom-center-common 主要提供环境, 事件, 项目启动, 数据转换等功能
atom-center-core 提供反射, 基础实体, JSON 处理, 枚举, Bean 操作等
atom-center-dependencies 管理此项目的依赖, 业务端使用此模块即可, 无需关心版本号
atom-center-devtools 代码自动生成
atom-center-notify 通知相关基础接口相关实体
atom-center-test 提供 Mock 与项目单元测试相关工具类, 通过一个注解即可实现集成测试
atom-center-validation 正则, 参数验证, 分组验证等
atom-center-structure 常用设计模式的封装
atom-center-spi java SPI 的封装

2.3.4 IDE 插件

为提供开发效率, 我们将一些常用操作通过 IDE 插件的方式进行简化, 将以前复杂的操作以自动化或少量步骤来代替, 进一步节约开发时间。

2.3.4.1 包含模块
插件 介绍
atom-idea-commit git commit 提交规范检查
atom-idea-common IDE 插件基础模块
atom-idea-format 统一代码样式插件
atom-idea-javadoc Javadoc 快速生成
atom-idea-patch 将部分代码打包成 jar, 以便于增量部署
atom-idea-root IDE 插件父项目

2.3.5 技术组件

在业务开发中, 经常使用到一些通用的功能, 没有基础框架之前如果需要复用功能, 需要将代码硬拷贝到另一个工程,然后重新集成一遍。 为了提供代码复用性, 增强代码可维护性, 我们封装大量常用的技术组件, 业务端只需要引入一个简单的依赖即可使用, 还根据公司环境替换了默认配置, 这样业务端引入就可以使用, 大大减少了重复配置的时间。

另一方面, 对于复杂依赖关系,手动管理所有项目依赖并不理想,容易出现许多问题, 可能需要花费大量的时间去排查依赖问题, 而技术组件能够引入关联的间接依赖, 减少业务端的依赖配置。

技术组件能够以一种开箱即用的方式支撑业务开发, 减少重复的集成工作, 目前已有组件如下:

2.3.5.1 包含组件
组件 介绍
atom-starter-auth 认证组件, 依赖后自动提供登录等相关接口, 减少业务端重复的登录接口逻辑编写
atom-starter-dependencies 技术组件依赖管理模块, 配置了大量常用的依赖版本, 集中解决依赖版本冲突的问题
atom-starter-cache 缓存组件, 提供分布式锁, 分布式缓存, Redis 订阅 / 发布模型, 二级缓存等功能
atom-starter-captcha 验证码组件, 提供普通验证码, 动态验证码, 并配套提供验证码检查等接口
atom-starter-doc 文档生成组件, 为接口层服务, 中台服务, RPC 服务提供接口文档一键生成, 减少手动编写接口时间
atom-starter-email 邮件组件, 支持发送普通邮件, 富文本邮件, 附件邮件
atom-starter-enhance-starter 增加组件, 将相关的技术组件合并为一个单独的依赖, 减少业务端引入依赖的数量
atom-starter-id 分部署 ID 生成组件, 能够高效的生成分布式 ID, 提供多种 ID 生成算法, 满足多种业务场景
atom-starter-idempotent 幂等组件, 解决业务上常见的接口请求幂等性判断
atom-starter-ip2region IP 转地理位置组件, 能力快速的通过 IP 查询对应的地理问题, 主要用于安全检查
atom-starter-launcher 启动组件, 简化了 Spring Boot 的启动类写法, 并提供默认配置的注入, 是所有项目的基础依赖
atom-starter-logsystem 日志组件, 提供全局的日志配置, 减少业务端的配置文件数量, 并提供审计日志接口, 减少业务端重复的审计日志需求开发
atom-starter-metrics 指标度量组件, 用于监控服务的各种指标是否正常, 也可添加业务指标, 用于统计
atom-starter-mq 消息组件, 提供 Kafka, RocketMQ 的集成并暴露统一的接口, 业务端可无感知使用
atom-starter-mybatis-dynamic 数据库操作组件, 可在不重启服务的情况下动态创建数据源
atom-starter-mybatis-mutli 数据库操作组件, 提供多数据源支持
atom-starter-mybatis 数据库操作组件, 封装常用的 list, page, 流式查询, SQL 慢查询, 非法 SQL 拦截, 分页等常用功能
atom-starter-qrcode 二维码组件, 提供二维码生成接口, 比可自定义二维码生成样式
atom-starter-rest API 层接口组件, 提供异常全局处理, 统一响应的数据结构, 参数校验, 参数转换, XSS 安全过滤等常用功能
atom-starter-retry 重试组件, 可通过配置在发生服务调用异常时自动重试功能
atom-starter-schedule 分布式定时任务组件, 可通知一个简单的组件声明任务, 然后通过配置的方式触发任务执行时间, 并提供 web 端管理所有的定时任务, 可实时监控任务执行情况
atom-starter-security 安全组件, 提供接口权限检验, 数据权限校验, 动态加载安全校验规则等功能
atom-starter-sms 短信组件, 集成了阿里云, 腾讯云和亿美等短信服务商接口, 减少业务端集成逻辑, 一键发送短信
atom-starter-template starter 技术组件模板, 规范与简化技术组件的编码方式, 业务端可使用此模板编写业务上的组件并实现复用

3. 开发计划

整体的开发计划分为 4 个季度, Q1 主要目标是根据 配电监测 需要使用的技术栈进行开发, 主要涉及到 Launcher, Logsystem, REST, Mybatis 4 个 starter 组件.

为了保证以上 4 个组件的正常使用, 还必须完成 builder 和 center 层的开发.

20241229154732_e9dOoXni.webp

4. 代码规范

代码规范的意义在于提高代码的严谨性,减少 bug 的产生; 促进团队之间的合作,交流方便; 降低维护成本; 有助于代码审查; 提高代码的规范性,有利于提高程序员的自我成长.

因此制定一个符合自己公司情况的开发规范,认识到代码规范的重要性,坚持规范的开发习惯。

这部分会在 Q2 启动.

5. 其他

5.1 技术文档

基础框架不仅仅只是交付可用的代码, 必须配套交付结构清晰, 语义明确的技术文档, 一方面是让团队快速上手开发, 另一方面是作为团队的技术沉淀, 因此会使用 开源工具 构建团队的 wiki 知识库, 提供提升团队的技术实力.