private plot

应无所住 | 而生其心

RuoYi 项目模块划分与依赖传递总结

RuoYi 是一个经典的 Java 后台管理框架,模块化设计是其核心之一。如何合理划分模块、处理模块间依赖、明确工具类和服务的归属,对于构建可维护、易扩展的系统尤为关键。


🗂 模块划分原则

1️⃣ 按职责分层划分

模块 说明
ruoyi-common 通用工具、基础封装、无状态方法、第三方 SDK 集成
ruoyi-framework Web 框架封装:Spring Boot、Spring Security、MyBatis 等适配层
ruoyi-system 系统级服务模块:用户、角色、菜单、字典、OSS、邮件等
ruoyi-generator 代码生成器模块,用于 CRUD 快速生成
ruoyi-quartz 定时任务调度模块
ruoyi-job (可选)业务级定时任务逻辑
ruoyi-api 对外接口层(微服务版拆出)
ruoyi-admin Web 管理后台主入口

单体版:模块组合在一个应用内;
微服务版:模块拆分成独立微服务,通过 OpenFeign 调用。

2️⃣ 按依赖关系层次划分

  • common最底层,不依赖其他业务模块;
  • framework → 依赖 common
  • system → 依赖 commonframework
  • admin → 依赖 system,但不应反向依赖。
1
2
3
4
graph TD
common --> framework
framework --> system
system --> admin

🔗 模块间依赖传递策略

工具类依赖传递

  • ruoyi-common
    • 示例:DateUtils, BeanUtils, RedisUtils
    • 无状态、线程安全。
  • 其他模块通过依赖 common 引入工具类。

服务依赖传递

  • ruoyi-system
    • 示例:SysEmailService, SysOssService
    • 系统能力服务,提供统一业务入口。
  • 其他模块通过依赖 system 调用服务接口。

🚨 禁止反向依赖

比如 system 不应依赖 admin,否则会导致模块耦合,难以拆分。


🛠 工具类 vs 服务放置原则

类型 推荐模块 说明
工具类 common/utils 纯工具封装,无状态逻辑
封装 SDK common 第三方 SDK 初始化,如邮件、OSS 的底层封装
系统级服务 system/service 有状态、需读取配置表(如 sys_config
业务逻辑服务 业务模块 针对具体业务逻辑实现,如订单、库存等

🌟 示例

📧 邮件发送

  • EmailUtilsruoyi-common
  • SysEmailServiceruoyi-system
  • 调用:SysEmailService.sendEmail(to, subject, content)

📦 OSS 存储

  • OssUtilsruoyi-common
  • SysOssServiceruoyi-system
  • 调用:SysOssService.upload(file)

📖 总结

  • 🏗 模块职责单一,工具类与服务层分离;
  • 🚫 禁止模块间环形依赖
  • ✅ 通用封装放 common,系统能力放 system
  • ⚡ 微服务化后,system 可拆为独立服务(如 OSS 服务、邮件服务)。

📌 参考

🏋️‍♂️ 徒手极简训练 7 天计划(10 分钟进阶版)

🗓 训练频率

  • 每天 10~15 分钟
  • 适合基础版适应后进阶使用

🕒 时间建议

场景 推荐时间
☀️ 早晨 起床后 10 分钟(喝水后再做)
🌙 晚上 晚饭后适度训练(不影响睡眠)
📱 白天碎片时间 工作间隙站起来活动,1~2 分钟即可

📅 每日训练动作(循环 2 轮)

🗓 Day 1 / Day 4

  1. 站姿开合跳 🦘 - 30 秒
  2. 高抬腿 🚶‍♂️ - 30 秒
  3. 标准俯卧撑 💪 - 8~10 次
  4. 站立体前屈伸展 🧘 - 保持 20 秒

🗓 Day 2 / Day 5

  1. 深蹲 🦵 - 12 次
  2. 肩部绕环 🔄 - 前后各 10 次
  3. 站姿体侧伸展 ↔️ - 左右各 15 秒
  4. 平板支撑 💪 - 保持 20~30 秒

🗓 Day 3 / Day 6

  1. 原地快走或开合跳 🚶‍♀️ - 1 分钟
  2. 箭步后撤 🦵 - 每条腿 8~10 次
  3. 俯身肩部伸展 🧘 - 左右各保持 15 秒

🗓 Day 7(恢复+放松日)

  • 颈部放松(点头/摇头各 5 次)
  • 腰背放松(站姿猫牛式,左右转动腰部各 5 次)
  • 原地慢走 3 分钟

📌 注意事项

  1. 每天动作循环 2 轮,总计约 10~12 分钟
  2. 饭后建议间隔 30~60 分钟
  3. 可根据状态适当调整组数和时长

🏋️‍♂️ 徒手极简训练 7 天计划(5 分钟版)

🗓 训练频率

  • 每天 5~8 分钟
  • 随时随地可做,不受环境限制

🕒 时间建议

场景 推荐时间
☀️ 早晨 起床后 5 分钟(喝水后再做)
🌙 晚上 晚饭后站立做一轮(轻松无负担)
📱 白天碎片时间 工作间隙站起来活动,1~2 分钟即可

📅 每日训练动作

🗓 Day 1 / Day 4

  1. 站姿开合跳 🦘 - 30 秒
  2. 高抬腿 🚶‍♂️ - 30 秒
  3. 跪姿俯卧撑 💪 - 8~10 次
  4. 站立体前屈伸展 🧘 - 保持 15 秒

🗓 Day 2 / Day 5

  1. 深蹲 🦵 - 10 次
  2. 肩部绕环 🔄 - 前后各 10 次
  3. 站姿体侧伸展 ↔️ - 左右各 10 秒
  4. 平板支撑 💪 - 保持 10~15 秒

🗓 Day 3 / Day 6

  1. 原地快走 🚶‍♀️ - 1 分钟
  2. 箭步后撤 🦵 - 每条腿 6~8 次
  3. 俯身肩部伸展 🧘 - 左右各保持 10 秒

🗓 Day 7(恢复+放松日)

  • 颈部放松(点头/摇头各 5 次)
  • 腰背放松(站姿猫牛式,左右转动腰部各 5 次)
  • 原地慢走 2 分钟

📌 注意事项

  1. 重点在坚持,哪怕只做 1~2 个动作
  2. 饭后建议间隔 30~60 分钟
  3. 感觉疲劳时减少重复次数

便当搭配组合表

一、食材分类

1. 蛋白质类(中午带饭)

  • 鸡蛋
  • 豆腐
  • 虾仁
  • 腐竹
  • 牛肉

备注:虎头虾和三文鱼为周末偶尔食用,不纳入日常带饭食谱。

2. 蔬菜类

  • 西兰花
  • 花菜(菜花)
  • 芹菜
  • 胡萝卜
  • 紫甘蓝
  • 红甜椒

3. 主食类

  • 米饭(中午主食)

备注:紫薯、红薯、玉米等粗粮为早餐使用,不纳入中午主食搭配。

4. 调味及油脂类

  • 菜籽油
  • 橄榄油(适合低温炒菜或拌熟食)
  • 姜丝
  • 花椒
  • 低盐调味

二、搭配组合与做法

组合1:豆腐+西兰花+红甜椒+米饭

  • 做法
    • 豆腐切块焯水,用姜丝和花椒爆香炒制。
    • 西兰花焯水,红甜椒切丝同炒。
    • 出锅后可淋少量橄榄油增香。
    • 配白米饭装盒。

组合2:虾仁+芹菜+胡萝卜+米饭

  • 做法
    • 虾仁用盐和料酒腌制10分钟。
    • 芹菜、胡萝卜切片热炒,加入虾仁炒至变色。
    • 用少量橄榄油炒制更清爽。
    • 配白米饭装盒。

组合3:腐竹+花菜+紫甘蓝+米饭

  • 做法
    • 腐竹泡发后炒制,加入姜丝花椒提香。
    • 花菜、紫甘蓝焯水后翻炒。
    • 装盒后可适量淋橄榄油拌匀。
    • 搭配米饭,清淡健康。

组合4:鸡蛋+西兰花+胡萝卜+米饭

  • 做法
    • 鸡蛋煎成蛋饼切块。
    • 西兰花焯水,胡萝卜丝快炒。
    • 最后统一加橄榄油拌匀或分层装盒。
    • 与米饭搭配。

组合5:牛肉+芹菜+红甜椒+米饭

  • 做法
    • 牛肉切片,用生抽、料酒、姜丝腌制10分钟。
    • 芹菜、红甜椒切丝热炒,加入牛肉快炒至熟。
    • 全程使用菜籽油或橄榄油皆可。
    • 配米饭装盒,香气浓郁,蛋白质充足。

三、备注

  • 中午主食为米饭,控制分量,维持饱腹但不负担。
  • 粗粮如紫薯、红薯、玉米安排在早餐食用。
  • 所有蔬菜建议焯水后快炒,保留营养与口感。
  • 橄榄油适合用于熟食后拌匀或中低温快炒,搭配清淡便当尤佳。
  • 蛋白质可提前准备提升效率,调味以清淡为主。
  • 周末偶尔食用虎头虾、三文鱼;番茄晚上食用,不入便当。

本文将持续更新,根据食材变化、搭配优化及饮食经验进行维护记录。

在成长的路上,减少冗余、聚焦主线 是一项长期必修课。
这些是从chatgpt记忆里导出的内容,用于备份


🧠 为什么要清理记忆?

随着多个项目同时进行、生活节奏交错推进,我的系统记忆中积累了大量信息,逐渐变得冗余、重复,甚至出现冲突。为此,我主动开启了一次系统性的精简行动,目的是:

  • 清除重复、过时、已冻结的内容
  • 合并知识节点,提升整体认知结构清晰度
  • 腾出空间,容纳更新、更重要的信息
  • 其实最主要的原因是非订阅版的chatgpt记忆空间有限,我觉得这是chatgpt的bug,作为这么厉害的大预言模型,完全可以精简归纳记忆体内容,从而减少空间占用

🧩 精简后的核心内容

✅ 主线方向

  • AI 服务平台(askairo.com:构建一个服务跨境电商场景的本地智能系统,整合模型调用、LangChain、提示词优化等能力。
  • 已部署本地 Gemma 3 1B 模型,采用 Spring Boot + MySQL 构建完整客户端。

✅ 支撑基础

  • CS / AI 学习计划:长期推进,融合 AI 应用与理论知识补全。
  • lang-ast-analyze 项目:语法树分析 + 编译原理 + 自然语言学习。
  • 算法书项目:企业实战算法清单,整理为 Markdown Roadmap。

✅ 副线成长项目

  • 博客优化(blueshadex.com:持续打磨样式、SEO、阅读体验。
  • 家庭私有云:以 Tailscale + Syncthing + Jellyfin 为核心,搭建远程访问系统。

🧘 风格与节奏

  • 偏好传统项目结构,Clean Code 原则深入实践。
  • 默认 JDK 8,结构清晰、易于测试。
  • 每周设有“复盘模板”,类似禅修式陪练机制。

🍱 生活同步:90 天逆转计划

  • 午餐便当:西兰花、芹菜、花菜、腐竹、紫甘蓝、红甜椒、豆腐、虾仁,主食以米饭为主,低盐低油。
  • 早餐轮换:鸡蛋、牛奶、紫薯/玉米,水果收尾。
  • 晚上节制,偶尔补充坚果、深色蔬菜,周末加虎头虾、三文鱼。

🌿 审美与身份

  • 哀愁而含蓄的东方式美学,是我心灵的归属(《红楼梦》《边城》)。
  • Kairo 是我偏爱的名字,定生二字,是我对生命状态的期许。

🔚 小结

这次记忆精简行动,不只是一次数据管理,更是对自己认知结构的重塑。愿以更轻盈、更清晰的内在架构,走向下一阶段。

“删繁就简三秋树,领悟方向一叶舟。”

引言

在业务系统的高并发读写压力下,合理架构数据库系统成为系统稳定性与可扩展性的关键。本文从 OLTP、OLAP、HTAP 三类架构模型出发,逐步探讨主流解决方案的适用场景,最终回归到底层数据结构和事务引擎的设计哲学。


一、OLTP、OLAP、HTAP 的关系与区别

OLTP(Online Transaction Processing)

  • 面向高并发、实时写入与读取。
  • 典型场景:订单系统、支付系统。
  • 特点:小事务、快速响应、数据一致性强。

OLAP(Online Analytical Processing)

  • 面向数据分析与多维查询,重读操作。
  • 典型场景:报表分析、BI 系统。
  • 特点:复杂查询、大数据量聚合、写入延迟可接受。

HTAP(Hybrid Transactional and Analytical Processing)

  • 目标:在同一系统中同时支持 OLTP 与 OLAP。
  • 代表系统:TiDB、SingleStore、Doris。
  • 难点:一套引擎既要保证事务一致性,又要提供分析性能,成本高、复杂度高。

总结:

架构 主要目的 数据延迟容忍 一致性要求 查询复杂度 应用类型
OLTP 快速写入与查询 简单 订单、库存系统
OLAP 多维分析 可容忍 弱/最终一致性 报表、BI分析
HTAP 统一处理混合负载 低至中等 中等至高 通用大数据平台

二、读写分离方案与数据分析架构

读写分离(MySQL 主从 + ShardingSphere-JDBC)

  • 主节点专职写,从节点负责读,通过代理层实现透明路由。
  • 适用场景:业务系统中读请求远大于写请求,提高系统吞吐量。
  • 特点:
    • 快速部署,技术成熟。
    • 只能提升读性能,写性能无法提升。
    • 一致性依赖 binlog 异步复制,存在数据延迟。

OLTP + ETL + OLAP 架构

  • ETL:周期性从 OLTP 拉取数据,清洗加工后写入数据仓库。
  • OLAP:在数据仓库中进行高复杂度查询与分析。
  • 优点:读写解耦,业务与分析隔离,灵活可扩展。
  • 缺点:数据同步延迟(分钟级、小时级),一致性难保证。

三、读写冲突的本质

读写冲突的根源是结构的共享与修改竞争

  • 读操作依赖于当前数据结构(如索引树),要求一致性。
  • 写操作修改数据结构(新增记录、变更索引节点)。
  • 写涉及加锁、日志、索引更新;读为了事务隔离也需要锁或快照。
  • 二者对相同数据结构的访问模式不同,引发冲突。

四、InnoDB 如何减少读写冲突:MVCC 机制

InnoDB 实现了多版本并发控制(MVCC)来减少锁冲突,关键字段:

  • trx_id:表示该版本由哪个事务创建。
  • roll_pointer:指向上一个旧版本的数据。
  • undo log:通过回滚指针形成历史版本链表。
  • 快照读(Snapshot Read):读取满足版本可见性的数据版本。
  • 当前读(Current Read):必须加锁,例如 SELECT ... FOR UPDATE

**可重复读(RR)**通过 MVCC 实现无需加锁的快照读取,兼顾一致性与并发性。


五、索引的结构设计:为什么选择 B+ 树

InnoDB 的索引(聚簇与辅助索引)采用 B+ 树实现,原因如下:

相比 B 树:

  • 所有数据仅存在叶子节点,内节点只存储 key,占空间更小,分支因子更高,更适合磁盘存储。
  • 叶子节点之间通过链表连接,天然支持范围查询。

相比红黑树:

  • B+ 树为多路平衡树,树高更低,磁盘访问更少
  • 红黑树为二叉树,在大数据量下树高过深,不适合磁盘场景

六、三种结构直观对比

特性 B 树 B+ 树 红黑树
数据存储位置 所有节点都可存 只在叶子节点存储数据 所有节点存储数据
查询效率 高效(叶子节点链表)
范围查询 最优 最差
适用场景 磁盘索引 数据库、文件系统索引 内存数据结构(TreeMap 等)

推荐阅读:


结语

读写冲突、索引设计、事务并发控制,这些数据库内部机制是我们构建健壮系统的基石。掌握这些原理不仅能设计出更高效的系统架构,也有助于我们在性能瓶颈中找到最优解法。

主结构

本文记录一次对 Spring Boot 项目中 Logback 配置的优化过程,围绕如下目标展开:

  • 控制台 + 文件双输出
  • INFO / WARN / ERROR 日志分级输出
  • 用户行为日志单独归档
  • 区分开发与生产环境的日志级别(dev 为 DEBUG,prod 为 WARN)
  • 日志格式统一、结构清晰,方便后期问题排查与行为分析

日志配置结构与关键实现

基础配置

1
2
<property name="log.path" value="/home/kairo/logs"/>
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>

控制台输出

1
2
3
4
5
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>

分级输出文件:INFO/WARN 与 ERROR 拆分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<appender name="file_info" class="...RollingFileAppender">
<filter class="...LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>NEUTRAL</onMismatch>
</filter>
<filter class="...LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>

<appender name="file_error" class="...RollingFileAppender">
<filter class="...LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>

用户行为日志单独输出

1
2
3
4
5
6
7
8
<appender name="sys-user" class="...RollingFileAppender">
<file>${log.path}/sys-user.log</file>
...
</appender>

<logger name="sys-user" level="INFO">
<appender-ref ref="sys-user"/>
</logger>

环境隔离配置(开发用 DEBUG,生产用 WARN)

1
2
3
4
5
6
<springProfile name="dev">
<logger name="com.kairo" level="DEBUG"/>
</springProfile>
<springProfile name="!dev">
<logger name="com.kairo" level="WARN"/>
</springProfile>

关键问题深度剖析

✅ 1. springProfile 不生效的排查逻辑

现象:在 dev 环境下指定 logger.level=DEBUG 无效。

原因与排查:

  • 检查 application.yml 中是否重复配置 logging.level,会覆盖 logback 的 logger 设置
  • **springProfile 标签仅作用于 <logger>,**不作用于 <root>
  • <springProfile> 标签不能嵌套在 <root> 外部,只能出现在 <logger> 外部,只能控制类或包级别日志,不控制 appender 或 root。

建议:使用 <springProfile> 时必须绑定 <logger>,用于区分环境中 logger 的级别控制。


✅ 2. root 与 logger 的职责区分:输出 vs 定位

  • <root> 是日志系统的兜底配置,当 logger 找不到匹配项时,将使用 root 的日志级别及输出配置。
  • <logger> 是针对特定类或包名(如 com.kairo)做更细粒度的日志级别控制。
  • 简单说:logger 控制日志“来源”,root 控制日志“去向”(默认路径和等级)

✅ 3. logger 优先级高于 root,合理组合精细化配置

  • 如果某个类或包使用了 <logger> 配置,则 root 的配置将不再生效
  • 仅当未指定 <logger> 时,root 才会起作用。
  • 合理做法是:关键业务模块用 logger 精细配置,其他模块用 root 兜底。

✅ 4. logger / root / appender + filter 三者关系

元素 控制内容 粒度 备注
logger 控制日志来源(类/包) 可环境隔离配置
root 控制日志兜底来源 不能用 springProfile 隔离
appender + filter 控制日志输出去向(文件/控制台)和级别 输出端 是最终的过滤逻辑

核心结论:最终能不能输出,还要通过 appender 的 LevelFilter 筛一遍,即使 logger 放行了,如果 filter 不放行也无法写出。


✅ 5. 环境隔离要基于 logger 做

  • 不能用 springProfile 控制 root 的输出级别
  • 需要将 logger 包名配置明确,并分别在 dev / prod 环境下赋予不同级别。
  • 建议约定所有业务日志均以统一包名开头,例如 com.kairo,方便统一配置。

附录(可选)

logback.xml配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 日志存放路径 -->
<property name="log.path" value="/home/kairo/logs"/>
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>

<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>

<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:继续交由后续 filter 判断是否接收 -->
<onMismatch>NEUTRAL</onMismatch>
</filter>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>WARN</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>

<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>

<!-- 用户访问日志输出 -->
<appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-user.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>


<!-- ============================== 输出渠道日志级别控制 ============================== -->

<!-- 根日志输出级别(“兜底”的默认级别控制器,仅对没有单独指定 logger 的类或包生效,配合appender里的filter使用) -->
<root level="INFO">
<appender-ref ref="console"/>
<appender-ref ref="file_info"/>
<appender-ref ref="file_error"/>
</root>
<!--系统用户操作日志(单独控制,记录登录等)-->
<logger name="sys-user" level="info">
<appender-ref ref="sys-user"/>
</logger>


<!-- ============================== 资源日志级别控制(<logger> 的级别优先于 <root>,控制的是包或类级别的日志输出) ============================== -->

<!-- 区分环境的包控制 -->
<!-- 开发环境,日志级别控制 -->
<springProfile name="dev">
<logger name="com.kairo" level="DEBUG"/>
</springProfile>
<!-- 其他环境,日志级别为 warn -->
<springProfile name="!dev">
<logger name="com.kairo" level="WARN"/>
</springProfile>

<!-- 不区分环境的包控制 -->
<!-- framework日志控制 -->
<logger name="org.springframework" level="WARN"/>
<logger name="springfox.documentation.spring.web" level="WARN"/>
<logger name="org.activiti" level="WARN"/>
<logger name="org.quartz" level="WARN"/>
<!-- 特定业务日志精细控制 -->
<logger name="com.kairo.oms" level="INFO"/>
<logger name="com.kairo.stat" level="INFO"/>

</configuration>

日志输出样例

1
2
12:01:23.456 [main] INFO  c.z.s.controller.LoginController - [login,42] - 用户登录成功,userId=123
12:01:25.789 [main] ERROR c.z.s.service.OrderService - [submitOrder,88] - 下单失败:库存不足

推荐日志目录结构

1
2
3
4
/home/kairo/logs/
├── sys-info.2025-05-17.log
├── sys-error.2025-05-17.log
├── sys-user.2025-05-17.log

总结

本次 Logback 优化实现了以下能力:

  • 分级、分模块、分环境的日志输出
  • 控制台与文件并行输出
  • 可扩展性强,支持后续 JSON 格式或 ELK 接入
  • 易于维护与排错,结构清晰

特别注意多个配置项之间的交互逻辑,掌握“logger 控源,filter 控流,root 兜底”的思维模型,有助于写出稳定、灵活的日志配置方案。

背景

在项目接口设计过程中,团队成员对于接口 URL 命名风格存在分歧:是否应采用 camelCase(驼峰命名)?对此展开了讨论。


结论

接口 URL 不应使用驼峰命名(camelCase),推荐统一采用 小写 + 中划线(kebab-case) 风格,或根据项目团队的规范选择使用下划线(snake_case),但应保持一致性。


理由分析

1. URL 是大小写敏感的

  • /userInfo/userinfo 被视为不同资源,易引发错误。
  • 驼峰风格加剧了大小写混淆的风险。

2. REST 社区与业界共识

  • 主流 RESTful API 设计(GitHub、Stripe、Twitter 等)均采用 kebab-case。
  • 阿里巴巴《Java 开发手册》、Google API 设计文档均推荐使用中划线分词。

3. 可读性更优

  • user-infouserInfo 更直观显示单词边界。
  • 相比下划线 _,中划线 - 在浏览器中的可视效果更明显、更美观。

4. SEO 更友好

  • 搜索引擎(如 Google)明确推荐使用中划线分隔词,避免使用下划线。
  • kebab-case 能被识别为多个关键词,有利于网页检索。

5. 为什么不推荐使用下划线(snake_case)

虽然下划线在数据库字段命名中很常见,但在 URL 中使用存在如下问题:

  • 不利于 SEO
    Google 明确表示:中划线被视为“词边界”,下划线不会;即 /user-info 会被当作两个词,而 /user_info 会被当作一个词。

  • 可读性差
    下划线在链接中经常被渲染为“不可见”或与底线混淆(尤其在下划线带超链接时),不如中划线易于识别。

  • 不符合社区主流
    主流框架和 API 设计规范文档均推荐使用 kebab-case,而非 snake_case。

6. 阿里巴巴 Java 开发手册的推荐

根据阿里巴巴的 Java 开发手册(《中册》)规定:

  • URL 地址命名风格推荐使用下划线分隔单词,并且全部小写。
  • 示例:/query_user_info/register_device_token

阿里规范与社区主流差异

  • 阿里规范:推荐使用下划线(snake_case)。
  • RESTful API 规范:社区主流(例如 GitHub、Stripe)推荐使用中划线(kebab-case)。

这两者的差异反映了不同技术社区和团队的偏好,而在具体项目中,选择遵循哪种规范应考虑团队需求及一致性。

7. 统一风格提升可维护性

为了避免不同风格的混杂,建议根据项目需求选择一种命名风格,并在整个项目中保持一致。

场景 命名风格
URL 路径 kebab-case / snake_case(根据项目规范选择)
JSON 字段名 camelCase
数据库字段 snake_case
常量/枚举 UPPER_CASE

不推荐的命名风格比较

风格 是否推荐 原因简述
camelCase ❌ 不推荐 易混淆、大小写敏感
snake_case ✅ 推荐(阿里规范) 适用于数据库,但对 URL 不太友好
kebab-case ✅ 推荐(REST 社区主流) SEO 友好、可读性好、符合行业趋势

推荐阅读与参考资料


总结

URL 是接口设计中面向外部的重要部分,命名风格应符合通用标准。为了减少歧义、提升可维护性、增强可读性,推荐统一使用 kebab-case 风格定义接口 URL,或者根据团队的具体要求选择下划线(snake_case)风格,但需保持一致性,避免混合使用。

引言

Jeff Dean 是 Google 历史上最具影响力的工程师之一。他不仅是多个关键基础设施的第一作者或领导者,也长期主导 Google 的技术发展方向。从早年的分布式系统,到后来的机器学习框架与深度模型架构,他的工作体系贯穿了计算范式的两次重大转变。

本文将围绕 Jeff Dean 所参与的几篇关键论文,梳理其背后的技术体系和影响轨迹。


一、大数据时代:分布式计算基础设施的建立

1. The Google File System (2003)

  • 作者:Sanjay Ghemawat, Howard Gobioff, Jeff Dean
  • 贡献:首次系统性构建适用于廉价硬件的大规模分布式文件系统,为 Google 内部所有高吞吐服务提供了存储支撑。
  • 技术亮点:Chunk-based 存储、主控节点简化调度、自动副本管理容错。

2. MapReduce: Simplified Data Processing on Large Clusters (2004)

  • 作者:Jeff Dean, Sanjay Ghemawat
  • 贡献:提出了通用的分布式计算模型,将大规模数据处理抽象为 Map/Reduce 两个阶段。
  • 影响:成为 Hadoop 等系统的灵感来源,极大降低了分布式编程门槛。

3. Bigtable: A Distributed Storage System for Structured Data (2006)

  • 作者:Fay Chang, Jeffrey Dean 等
  • 贡献:构建高可扩展性的结构化存储系统,支撑搜索、地图、广告等核心服务。
  • 技术亮点:SSTable、Chubby、列式存储、自动分区与负载均衡。

Jeff Dean 亲自参与并主导了 Google 构建分布式计算三大支柱(GFS、MapReduce、Bigtable),确立了技术基础框架,影响了后来的云计算生态。


二、AI 时代:深度学习平台与模型架构的兴起

4. TensorFlow: Large-Scale Machine Learning on Heterogeneous Systems (2015)

  • 作者:Martín Abadi, Jeff Dean(主导 Google Brain)
  • 贡献:统一计算图、自动求导、多设备分布式训练,开启深度学习工业化。
  • 亮点:灵活图结构、支持 CPU/GPU/TPU、生态繁荣。

5. Attention is All You Need (2017)

  • 作者:Ashish Vaswani, Noam Shazeer, Jakob Uszkoreit 等(Google Brain/Research)
  • 背景:Transformer 模型的提出催生了 BERT、GPT、T5 等大语言模型。
  • Jeff Dean 的角色:当时领导 Google Brain,指导性推动 Transformer 等架构探索,形成从框架到模型的协同研发文化。

三、Jeff Dean 的工作体系特征

1. 系统思维主导的工程设计

  • 将“抽象”与“工程实现”深度结合,先后建立了 Google 的存储系统、计算框架、机器学习平台。
  • 每个系统都强调:扩展性、容错性、易用性

2. 注重论文产出与开源结合

  • 其工作不只是内部系统设计,还特别注重通过论文、白皮书、开源推动学术与工业的互动。
  • TensorFlow 即是科研与工程结合的代表产物。

3. 技术演进中的桥梁角色

  • 从 C++ 系统级工程,到 Go/TPU/AI 平台,Jeff Dean 始终是 Google 技术变迁中承上启下的枢纽人物。
  • 他倡导工程师参与研究、研究者深入工程,打造跨界团队。

四、小结:一个技术体系的缩影

从 GFS 到 TensorFlow,从 MapReduce 到 Transformer,Jeff Dean 的工作体系不仅见证,也构建了 Google 技术体系的脊梁。这些工作推动了两个时代的技术浪潮:

  • 分布式计算 → 云平台生态
  • 神经网络训练 → 通用 AI 架构

Jeff Dean 本人始终强调**“将抽象转化为生产力”**,这也是 Google 技术创新的一以贯之之道。


附录:涉及论文与链接一览

序号 论文标题 链接 发表年份
1 The Google File System 链接 2003
2 MapReduce: Simplified Data Processing on Large Clusters 链接 2004
3 Bigtable: A Distributed Storage System for Structured Data 链接 2006
4 TensorFlow: Large-Scale Machine Learning on Heterogeneous Systems 链接 2015
5 Attention is All You Need 链接 2017

0%