private plot

应无所住 | 而生其心

摘要
在多业务统一入口的场景中,业务类型动态分发与公共逻辑复用是核心挑战。本文总结一种优雅且高扩展的解决方案,涵盖两个重点:

  1. 基于自定义注解 + Spring容器 Bean 管理 + 代理兼容实现的策略模式
  2. 接口与抽象类配合,定义契约并复用公共实现,实现解耦和结构清晰

1. 注解驱动的策略注册机制(伪代码)

自定义注解

1
2
3
4
5
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface BizModel {
String value();
}

策略工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Component
public class StrategyFactory {

private Map<String, StrategyInterface> strategyMap = new HashMap<>();

public StrategyFactory(Map<String, StrategyInterface> strategies) {
for (StrategyInterface strategy : strategies.values()) {
Class<?> realClass = SpringAopUtils.getTargetClass(strategy);
BizModel annotation = realClass.getAnnotation(BizModel.class);
if (annotation != null) {
strategyMap.put(annotation.value(), strategy);
}
}
}

public StrategyInterface getStrategy(String key) {
StrategyInterface strategy = strategyMap.get(key);
if (strategy == null) throw new RuntimeException("未找到策略:" + key);
return strategy;
}
}

策略实现示例

1
2
3
4
5
6
7
8
9
@Service
@BizModel("业务标识1")
public class ConcreteStrategyA extends AbstractStrategyBase {

@Override
protected void doBusinessLogic(DTO dto) {
// 业务特有逻辑实现
}
}

2. 接口 + 抽象类的协同设计(伪代码)

定义接口(契约)

1
2
3
public interface StrategyInterface {
void execute(DTO dto);
}

抽象类(公共流程模板)

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
public abstract class AbstractStrategyBase implements StrategyInterface {

@Override
public void execute(DTO dto) {
validate(dto);
preProcess(dto);

doBusinessLogic(dto); // 子类实现差异化

postProcess(dto);
}

protected abstract void doBusinessLogic(DTO dto);

private void validate(DTO dto) {
// 公共校验逻辑
}

private void preProcess(DTO dto) {
// 公共预处理
}

private void postProcess(DTO dto) {
// 公共后处理
}
}

3. 运行时调用示意(伪代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RestController
public class Controller {

private final StrategyFactory factory;

public Controller(StrategyFactory factory) {
this.factory = factory;
}

public Response handleRequest(RequestDTO dto) {
StrategyInterface strategy = factory.getStrategy(dto.getBizModel());
strategy.execute(dto);
return Response.success();
}
}

总结

利用注解驱动 + Spring自动装配实现业务类型到策略实现的动态路由,方便扩展。
通过接口定义契约,抽象类封装公共流程,实现代码复用与解耦。
设计既减少重复代码,又保证系统灵活性和维护便利。

摘要
这是一篇对自己的复盘文章,从职业习惯、思维模式和生活方式三个角度,总结了我的优势与不足,并提出了具体的改进方法。核心关注点是如何在保持专业与细节追求的同时,降低完美主义带来的成本、提高沟通效率、减少任务切换的损耗。

前言

这篇文章是一次对自己的回顾与整理,结合近期的工作习惯、技术思路以及生活节奏,总结我是什么样的人、有哪些不足,以及针对不足的改进方向。


我的特点

  1. 专业能力强
    作为一名 Java 后端开发者,我在业务实现中注重代码质量,熟悉 Clean Code 原则,能写出简洁、易测、结构清晰的代码。对 SICP 这类计算机科学经典思想也有一定的理解,并在实践中贯彻。

  2. 逻辑严谨
    处理问题时习惯从原理层面切入,比较不同方案的优劣,而不是仅停留在能用的层面。

  3. 学习驱动
    主动钻研 SQL、网络、编译原理等底层知识,保持对技术细节的敏感。

  4. 生活有节奏
    饮食、作息相对稳定,有长期健康意识。

  5. 审美有取向
    偏好含蓄的东方美学,这种审美观也影响了我对代码和设计风格的追求——克制、简洁、有韵味。


我的不足

  1. 完美主义倾向
    常常在功能已可用的情况下,花额外精力去打磨细节。例如,在简单的字符串拼接中犹豫要不要用 String.format,或者在 Maven 打包已正常完成的情况下,仍想验证编译警告是否影响速度。这种追求虽然保证了质量,但容易在非关键环节投入过多时间。

  2. 信息密度过高
    在沟通时倾向一次性提供大量上下文与技术细节。虽然信息完整,但接收方需要先拆解再理解,降低了沟通效率。

  3. 任务切换成本高
    在深入一个任务后切换到另一任务时,需要花时间恢复思路。这与记忆力关系不大,更多是处理问题方式造成的:我倾向长时间深度专注,但缺少任务切换前的“外部缓存”动作。


改进方向

1. 优先级分层

  • 方法:使用“30 秒优先级评估法”快速判断当前优化是否影响核心功能或交付时间。
  • 目标:每天至少推迟 1 个非关键优化任务,观察是否对结果造成实际影响。

2. 降低信息密度

  • 方法:采用“3 段式提问法”——背景一句话、问题一句话、补充信息按需提供。
  • 目标:每天至少用一次 3 段式提问,评估反馈速度。

3. 减少切换损耗

  • 方法:切任务前,用 1-2 句话记录当前进度与下一步动作,作为外部缓存。
  • 目标:每天记录 3 次切换笔记,确保切回任务时能在 2 分钟内进入状态。

结语

这不是一次对自己的苛责,而是一次客观的整理与优化。
优势要保持,不足要改进,习惯要固化。
持续的小改进,会带来长期的大变化

在函数设计中,我们常常会遇到一个令人纠结的问题:参数的合法性由谁负责校验?

我们以如下函数为例:

1
2
3
4
5
6
7
8
9
10
public OmsMockResponse<String> pushBySynRecord(SynRecord synRecord) {
...
OmsInboundOrderResponse inbound = getOmsInboundOrder(order.getContainerNo());
if (inbound == null) {
return new OmsMockResponse<>(400, "未找到入库单", null);
}

OmsInboundExpectedDatePushRequest request = buildRequest(order, inbound);
...
}

🧩 1. 谁使用,谁负责
这是最基础的原则:

如果你要用某个值,比如调用 inbound.getInboundOrderNo(),你就要保证这个值有效。

因此,buildRequest 要负责检查 inboundOrderNo 是否为空,而不是调用者 pushBySynRecord。

✅ 谁使用字段,谁就对它的存在性和合法性负责。

🧩 2. 谁输出,谁负责
buildRequest 要负责返回一个结构完整、语义清晰的 Request 实例,它就要确保 expectedDate、inboundOrderNo 都不为空,哪怕调用者传了问题数据,也应该 fail fast。

✅ 被调用方有责任保证其输出对象的完整性。

🧩 3. 如果把参数换成基本字段值呢?
我们曾探讨如果将函数签名改为:

1
buildRequest(String scheduledWarehouseDate, String inboundOrderNo)

那么这两个值就变成调用方的直接输入参数,调用者必须明确检查:

1
2
3
if (StrUtil.isEmpty(inboundOrderNo)) {
...
}

因为:

✅ 当你传递的是原始值(如String/int),使用它的代码就是最懂它语义的地方,调用者应承担责任。

🧩 4. int vs Integer:如何选择
类型 使用场景
int 业务默认值清晰、内部使用不需要表达“缺省”
Integer 业务字段可以为 null(未赋值、未选择)/ 与数据库字段对应时

举例:

1
2
3
4
5
public class UserDTO {
private Integer age; // 可以不填,允许 null
}

int sum = 0; // 内部统计逻辑,始终初始化

✅ 总结
函数设计中参数校验职责的判断,并非生硬划分,而是结合语义、职责、契约综合判断:

原则 描述
谁使用谁负责 使用字段的地方负责其有效性
谁输出谁负责 函数必须确保其输出可用性
最小信任原则 被调用方不应信任调用方输入,必要时做 fail-fast 校验
类型语义选择 Integer 适用于业务不确定性表达;int 用于纯粹逻辑场景

最重要的是:保持函数职责清晰,边界明确,遵循契约精神。

常用 Git 分支管理、提交、合并、同步等命令的速查表,适合日常开发参考。

阅读全文 »

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 等)

推荐阅读:


结语

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

0%