沉淀知识,持续成长

记录 Java 后端、前端开发与 Linux 运维的每一次思考与实战踩坑。

Java Spring Boot Spring Cloud MySQL Redis Vue 3 React TypeScript Docker Kubernetes Nginx

📖 最新技术笔记

2026-09-14 Spring Boot

Spring Boot 自动装配原理深度解析

从 @SpringBootApplication 注解入手,分析 @EnableAutoConfiguration 如何通过 SPI 机制加载 META-INF/spring.factories 中的配置类...

2026-09-12 JVM

JVM 内存模型与垃圾回收机制总结

整理堆、栈、方法区的内存划分,以及新生代 Eden/Survivor 比例。重点记录 CMS 和 G1 收集器的适用场景与调优参数...

2026-09-08 MySQL

MySQL 索引优化与 Explain 执行计划分析

记录最左前缀原则、索引下推。通过 Explain 命令分析 type、key、rows 等字段,定位并解决慢 SQL 问题...

2026-09-05 Redis

Redis 缓存穿透、击穿与雪崩的解决方案

结合实际项目,总结布隆过滤器、互斥锁、逻辑过期等应对策略,以及如何通过多级缓存降低 Redis 压力...

2026-08-28 Java 并发

Synchronized 锁升级与 AQS 框架解析

从 JVM 字节码指令 monitorenter/exit 到 AQS 框架,对比两者的锁升级过程、公平锁与非公平锁的实现差异...

2026-08-20 Spring

Spring 事务失效的 8 种常见场景

方法非 public、自调用、异常被吞、事务传播行为配置错误等导致 @Transactional 失效的场景与排查思路...

2026-08-11 微服务

Spring Cloud Alibaba 微服务组件整合实战

整合 Nacos 作为注册中心和配置中心,OpenFeign 实现服务调用,Sentinel 实现限流降级,Gateway 统一网关...

2026-07-30 消息队列

Kafka 消息丢失与重复消费问题排查

从生产者 acks 机制、Broker 持久化,到消费者 offset 提交策略,全方位分析 Kafka 消息可靠性保障方案...

2026-09-13 Vue

Vue3 响应式原理:Proxy 与 Reflect 深度解析

对比 Vue2 的 Object.defineProperty,分析 Vue3 如何利用 Proxy 实现深层响应式,以及依赖收集与触发更新的流程...

2026-08-25 React

React Hooks 闭包陷阱与性能优化实践

记录 useState 异步更新、useEffect 依赖数组常见坑点,以及 useMemo、useCallback 在组件性能优化中的正确用法...

2026-08-18 TypeScript

TypeScript 泛型与高级类型实战总结

整理 Partial、Omit、Pick 等内置工具类型的实现原理,以及如何在项目中利用泛型约束提升代码类型安全性...

2026-07-18 性能优化

前端性能优化:从首屏加载到 Lighthouse 评分

通过路由懒加载、图片压缩、CDN 加速、Gzip 压缩等手段,将首屏加载时间从 3s 优化到 1s 以内的实战记录...

2026-07-05 工程化

Vite 与 Webpack 打包构建原理对比

分析 Vite 为什么在开发环境下冷启动如此之快(ESBuild + ESM),以及 Webpack 的依赖图谱构建流程差异...

2026-08-15 Docker

使用 Docker 部署 Spring Boot 项目实战

编写 Dockerfile,利用多阶段构建减小镜像体积。配置 docker-compose 一键启动 MySQL、Redis 和应用服务...

2026-08-08 Kubernetes

K8s 核心概念:Pod、Deployment 与 Service

从零开始理解 K8s 的编排模型,记录 Pod 生命周期、Deployment 滚动更新策略以及 Service 服务发现的配置...

2026-08-02 Linux

Nginx 编译安装后,Certbot 无法找到配置的解决方案

记录在非标准路径下编译安装 Nginx 时,如何通过软链接与参数指定,让 Certbot 正常签发 SSL 证书...

2026-07-28 Linux

Linux 排查 CPU 飙高的实用命令与思路

通过 top、pidstat、jstack 等工具,定位 Java 进程 CPU 100% 的具体线程与代码行,记录一次真实线上排查过程...

2026-07-25 Nginx

单页应用(SPA)路由回退原理与 Nginx 配置

为什么访问不存在的路径会返回首页?try_files 指令是如何工作的?本文记录一次实际踩坑过程...

2026-07-20 Shell

Shell 脚本自动化:定时备份 MySQL 与日志清理

编写 Shell 脚本结合 crontab,实现 MySQL 数据库每日自动备份、压缩,并清理 7 天前的旧日志与备份文件...

2026-07-15 监控

Prometheus + Grafana 搭建服务器监控系统

使用 Node Exporter 采集 Linux 主机指标,Prometheus 存储时序数据,Grafana 配置可视化大屏并设置告警规则...

2026-07-10 网站建设

个人网站从零到上线:域名备案与 HTTPS 配置全记录

整理从购买服务器、域名解析、提交 ICP 备案,到最终使用 Let's Encrypt 开启 HTTPS 的完整流程...

💡 常见技术问答

什么是跨域?如何解决跨域问题?
跨域是指浏览器出于安全考虑,阻止网页向不同源(协议、域名、端口任一不同)的服务器发起请求。解决方式主要有:
  • CORS:后端设置 Access-Control-Allow-Origin 等响应头。
  • Nginx 反向代理:通过同源服务器转发请求。
  • JSONP:老式方案,利用 <script> 标签不受同源策略限制。
  • 开发环境代理:如 Vite/Webpack 的 proxy 配置。
Vue2 和 Vue3 的响应式原理有什么区别?
  • Vue2:基于 Object.defineProperty 实现。缺点是无法监听对象属性的新增和删除,也无法监听数组下标的变化(需要重写数组方法)。
  • Vue3:基于 Proxy 和 Reflect 实现。可以代理整个对象,支持动态新增属性、删除属性,并且能完美监听数组变化,性能更好,且支持深层响应式。
Spring 是如何解决循环依赖的?
Spring 通过 三级缓存 来解决单例 Bean 的循环依赖问题:
  • 一级缓存 (singletonObjects):存放完全初始化好的 Bean。
  • 二级缓存 (earlySingletonObjects):存放提前暴露的、尚未填充属性的原始 Bean。
  • 三级缓存 (singletonFactories):存放 Bean 的 ObjectFactory,用于生成原始 Bean 或代理对象。
当 A 依赖 B,B 又依赖 A 时,A 在实例化后会将自身放入三级缓存,B 在创建时可以从三级缓存获取 A 的早期引用,从而打破循环。注意:Spring 无法解决构造器注入和原型(Prototype) Bean 的循环依赖。
什么是数据库的乐观锁和悲观锁?
  • 悲观锁:认为并发冲突一定会发生,操作数据时直接加锁(如 SELECT ... FOR UPDATE)。适合写多读少的场景。
  • 乐观锁:认为并发冲突不常发生,提交更新时才检查版本号或时间戳。适合读多写少的场景,通常通过 version 字段实现。
在实际项目中,MySQL 的 InnoDB 引擎通常推荐使用乐观锁来降低锁竞争,提升并发性能。
ThreadLocal 为什么会发生内存泄漏?
ThreadLocal 内部维护了一个 ThreadLocalMap,key 是 ThreadLocal 的弱引用,value 是强引用。如果 ThreadLocal 被回收,key 变成 null,但 value 仍然被 Entry 强引用,导致无法回收。而线程池中的线程复用,可能导致 value 越积越多,最终引发 OOM。

解决办法:使用完 ThreadLocal 后,务必在 finally 块中调用 remove() 方法清理。
如何保证缓存与数据库的双写一致性?
常见的策略有:
  • 先更新数据库,再删除缓存(Cache Aside Pattern):最常用,但在极端并发下仍有脏数据风险。
  • 延迟双删:更新数据库前后各删除一次缓存,并在中间加短暂延迟,降低脏数据概率。
  • 订阅 MySQL Binlog:如 Canal 监听数据库变更,异步刷新缓存,实现最终一致性。
  • 分布式锁:在更新时加锁,保证读写串行,但会牺牲性能。
如何排查 Linux 服务器 CPU 使用率过高的问题?
排查思路:
  • 使用 top 找到 CPU 最高的进程 PID。
  • 如果是 Java 进程,使用 top -Hp [PID] 找到占用 CPU 最高的线程 TID。
  • 将 TID 转为十六进制:printf "%x\n" [TID]。
  • 使用 jstack [PID] | grep [十六进制TID] -A 20 定位到具体代码行。
  • 如果是非 Java 进程,可使用 perf top 或 strace 分析。
Docker 和虚拟机有什么区别?
  • 虚拟机:在宿主机上模拟硬件,运行完整的操作系统,资源占用大,启动慢(分钟级),隔离性强。
  • Docker 容器:共享宿主机内核,通过 Namespace 实现隔离,Cgroups 限制资源。启动快(秒级),占用资源少,但隔离性弱于虚拟机。
容器更适合微服务架构下的快速部署和弹性伸缩。
Certbot 报错 "Could not find a usable 'nginx' binary" 怎么办?
通常是因为 Nginx 是编译安装的(如安装在 /usr/local/nginx),不在系统默认的 PATH 中。可以通过创建一个软链接(ln -s /usr/local/nginx/sbin/nginx /usr/local/bin/nginx),或者在运行 Certbot 时显式指定路径(如添加 --nginx-ctl 和 --nginx-server-root 参数)来解决。
Nginx 正向代理和反向代理的区别?
  • 正向代理:代理客户端,客户端知道自己在访问代理服务器,服务器不知道真正的客户端是谁(如翻墙工具)。
  • 反向代理:代理服务器端,客户端不知道自己在访问代理服务器,以为直接访问了目标服务器(如 Nginx 负载均衡)。