1、JDK版本

    A、推荐用JDK 21, 长期 LTS(虚拟线程、分代ZGC);
    B、追求稳定用JDK 17(生态极度成熟,全网踩坑案例最多,几乎无兼容雷区)

2、SpringBoot

    A、推荐用Spring Boot 3.3.13,存量项目基数极大,社区自发修复方案充足
      (3.4.x 停免费维护,依赖基线高,老中间件适配差,3.5.x 刚停免费维护,大量 Breaking 变更,生态兼容差);
    B、全新项目、中间件版本较新、团队能接受少量适配 → 优先 4.1.0(当前最新 GA 正式版)
      【所有中间件全部最新,无老旧第三方 SDK,刚发布 GA,国内微服务落地案例少,小众组件适配滞后;线上出问题排错资料稀缺】
    C、微服务、Nacos/Seata/MP 等国内组件多、不想踩新坑 → 选 4.0.7(4.0 分支最终稳定补丁)

3、JAVA 微服务架构

架构方案 完整技术栈 通信模式 注册配置中心 适用场景
首选 SpringBoot3 + Spring Cloud Alibaba + Nacos + Spring Cloud Gateway + OpenFeign 全链路HTTP Feign调用 Nacos(注册+配置一体) 能快速开发,中型项目架构,不追求极致高性能,
备选 SpringBoot3 + Spring Cloud Alibaba + Nacos + Spring Cloud Gateway + Dubbo3 外网HTTP、内网Dubbo RPC Nacos(注册+配置一体) 极致高并发要求,TPS要求3000+

注:Spring Cloud Alibaba 优势:一站式全家桶,减少中间件部署数量,运维成本低;
1、2023.x 系列官方唯一长期稳定生产版:2023.0.1.2
2、2023.0.3.x 是官方过渡开发分支,仅用于尝鲜新特性,未经过大规模线上验证,存在大量兼容性bug,社区不推荐业务系统直接上生产。
3、SCA 2025.0.x 硬性绑定 SpringBoot 3.5.x

4、微服务项目结构

    注:整体项目生态建议5个应用以内,如果一定有必要超出,则可以找架构组讨论. 参考项目如附件《hina-cloud-base》[项目规范demo]

项目介绍
文件结构

com.公司名.项目名.模块名为根文件目录,比如(com.hina.cloud.base为项目的根文件目录)

根文件目录下有springboot启动类,springboot默认扫描启动类所在文件目录及子文件目录

根文件目录下分为五个一级文件夹,分别为endpoint、common、config、application、domain,代表整个项目结构的五大模块

  • endpoint

    暴露的服务端点 微服务请求入口 来自不同客户端的服务接口应该区分开来,放在不同的子文件夹目录下,如:[web]、[h5]、[inner]。

其中web代表给web前端使用的接口,h5代表给移动端使用的接口,inner代表给内部其它微服务调用的接口。

之所以这样区分,是因为不同客户端请求对安全性的考虑不一样.
inner接口都是内部微服务之间调用,一般不考虑鉴权等问题.
对于web、h5端的请求都是来自网关转发, 而且都属于C端的请求, C端需要有用户注册、用户登陆态维护以及鉴权, 这些功能都被业务系统所前置.
所以一般后端服务不能暴露在公网上, 但是后端的服务又往往需要区分请求是来自哪个用户.
现在的通用做法是gateway或者auth系统通过token和用户id之间的转换放在http报文头中供后端业务系统使用, 这个特征在以H5为主要形态的移动端更为突出. 
http报文头往往还要承载更多属性和功能,基本需要Filter模块单独来处理, 比如说app的黑名单过滤、权限等功能, web端特别是管理系统就相对简单多.
所以把服务于不同客户端的请求接口分类开来, 方便开发.
  • application

    业务模块,endpoint是服务入口,application是业务得实现,跟业务相关的都放在这里面。其中manager文件夹用于放对事务封装的代码;

facade是调用外部服务的封装,业务代码直接使用封装api,屏蔽对事务已经外部服务调用所涉及的异常、熔断、结果处理等相关的细节处理,这样

使得业务代码逻辑更清晰,有利于代码的分层、重用和维护。

  • common

    公共模块,其它模块都能使用到的公共代码放在这里面,比如:枚举、异常、http 报文头的处理、filter、工具类等

  • config

    三方组件使用、配置模块,微服务更加推荐组件的启用、配置使用注解的方式引入,而不是传统的通过加载配置文件,因为前者更加高效。

  • domain

    领域模块,可以把这个模块理解为外交部,这里面是跟外部系统交互比较复杂,考虑的点比较多的代码,比如feign调用,数据库的使用,

业务模型的中间类、外部接口模型、数据模型等等,把他们放在一个模块里,便于统一维护管理。

5、项目编程规范

  • 参考《阿里巴巴Java开发手册.pdf》

6、数据库连接池配置

A、通用标准生产配置

  # 最小空闲连接,维持基础常驻连接,避免频繁创建销毁
  minimum-idle: 1
  # 连接池最大连接数,普通业务单服务标准值
  maximum-pool-size: 20
  # 获取连接等待超时时间,5秒拿不到连接直接抛出异常
  connection-timeout: 5000
  # 空闲连接超时:150秒自动回收;必须小于数据库wait_timeout(200s),防止产生僵尸连接
  idle-timeout: 150000
  # 连接最大生命周期:180秒强制销毁;同样小于数据库200s,预留安全缓冲
  max-lifetime: 180000
  # 连接泄漏检测阈值,超过3秒未释放打印日志,排查长事务/忘记释放连接
  leak-detection-threshold: 3000
  # 连接有效性校验超时,使用驱动原生isValid(),不要配置connection-test-query
  validation-timeout: 2000

B、并发专用 HikariCP

  # 高并发场景适当降低最小空闲,减少持续占用数据库连接;流量极度平稳可上调至10
  minimum-idle: 5
  # 核心上限:单服务30,务必统计集群所有实例总和,低于MySQL max_connections预留余量
  maximum-pool-size: 30
  # 获取连接超时,快速失败,避免线程长时间堆积;不建议低于1500ms
  connection-timeout: 3000
  # 空闲连接150s回收,严格小于数据库wait_timeout=200s,优先在DB断开连接前池子主动释放
  idle-timeout: 150000
  # 连接最长存活180s强制淘汰,规避TCP长时间空闲异常问题
  max-lifetime: 180000
  # 高并发缩短泄漏检测时间,尽早发现连接不释放问题
  leak-detection-threshold: 2000
  # 连接健康检测超时,底层使用TCP ping,无额外SQL开销
  validation-timeout: 2000

DBA 给出的标准

Namespace: OPERATION.{database_owner_upper}{databasename_upper}{limitupper}_C3P0

{database_owner}.{database_name}.{limit}.jdbc.driver = com.mysql.jdbc.Driver
{database_owner}.{database_name}.{limit}.jdbc.url = jdbc:mysql://{DNS_HOST}.baofoo.cn:3306/{database_name_upper}?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
{database_owner}.{database_name}.{limit}.jdbc.username.encrypt = {username_encrypt}
{database_owner}.{database_name}.{limit}.jdbc.password.encrypt = {password_encrypt}
{database_owner}.{database_name}.{limit}.jdbc.initialPoolSize = 1
{database_owner}.{database_name}.{limit}.jdbc.minPoolSize = 1
{database_owner}.{database_name}.{limit}.jdbc.maxPoolSize = 30
{database_owner}.{database_name}.{limit}.jdbc.acquireIncrement = 5
{database_owner}.{database_name}.{limit}.jdbc.maxIdleTime = 180
{database_owner}.{database_name}.{limit}.jdbc.maxStatements = 100

Namespace: OPERATION.{database_owner_upper}{databasename_upper}{limitupper}_HIKARI

{database_owner}.{database_name}.{limit}.jdbc.driver = com.mysql.jdbc.Driver
{database_owner}.{database_name}.{limit}.jdbc.url = jdbc:mysql://{DNS_HOST}.baofoo.cn:3306/{database_name_upper}?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
{database_owner}.{database_name}.{limit}.jdbc.username.encrypt = {username_encrypt}
{database_owner}.{database_name}.{limit}.jdbc.password.encrypt = {password_encrypt}
{database_owner}.{database_name}.{limit}.jdbc.minimumIdle=1
{database_owner}.{database_name}.{limit}.jdbc.maximumPoolSize=30
{database_owner}.{database_name}.{limit}.jdbc.idleTimeout=180000
{database_owner}.{database_name}.{limit}.jdbc.maxLifetime=1800000
{database_owner}.{database_name}.{limit}.jdbc.connectionTimeout=1000
{database_owner}.{database_name}.{limit}.jdbc.validationTimeout=1000
{database_owner}.{database_name}.{limit}.jdbc.keepaliveTime=60000

Namespace: OPERATION.{database_owner_upper}{databasename_upper}{limitupper}_DRUID

{database_owner}.{database_name}.{limit}.jdbc.driver = com.mysql.jdbc.Driver
{database_owner}.{database_name}.{limit}.jdbc.type = com.alibaba.druid.pool.DruidDataSource
{database_owner}.{database_name}.{limit}.jdbc.url = jdbc:mysql://{DNS_HOST}.baofoo.cn:3306/{database_name_upper}?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghai
{database_owner}.{database_name}.{limit}.jdbc.username.encrypt = {username_encrypt}
{database_owner}.{database_name}.{limit}.jdbc.password.encrypt = {password_encrypt}
{database_owner}.{database_name}.{limit}.jdbc.initialPoolSize = 1
{database_owner}.{database_name}.{limit}.jdbc.minIdle = 1
{database_owner}.{database_name}.{limit}.jdbc.maxActive = 30
{database_owner}.{database_name}.{limit}.jdbc.filters = stat,wall,log4j
{database_owner}.{database_name}.{limit}.jdbc.maxWait = 6000
{database_owner}.{database_name}.{limit}.jdbc.timeBetweenEvictionRunsMillis = 60000
{database_owner}.{database_name}.{limit}.jdbc.minEvictableIdleTimeMillis = 180000
{database_owner}.{database_name}.{limit}.jdbc.validationQuery = SELECT 1 FROM DUAL
{database_owner}.{database_name}.{limit}.jdbc.testWhileIdle = TRUE
{database_owner}.{database_name}.{limit}.jdbc.testOnBorrow = FALSE
{database_owner}.{database_name}.{limit}.jdbc.testOnReturn = FALSE
{database_owner}.{database_name}.{limit}.jdbc.poolPreparedStatements = TRUE
{database_owner}.{database_name}.{limit}.jdbc.maxOpenPreparedStatements = 20
{database_owner}.{database_name}.{limit}.jdbc.mergeSql = TRUE
{database_owner}.{database_name}.{limit}.jdbc.slowSqlMillis = 5000