<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>编程 on 洛克里亚的五度 博客</title>
    <link>https://lv-blog.pages.dev/categories/%E7%BC%96%E7%A8%8B/</link>
    <description>Recent content in 编程 on 洛克里亚的五度 博客</description>
    <generator>Hugo</generator>
    <language>zh</language>
    <lastBuildDate>Tue, 28 Jul 2026 13:40:09 +0800</lastBuildDate>
    <atom:link href="https://lv-blog.pages.dev/categories/%E7%BC%96%E7%A8%8B/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>理解MySQL的MVCC</title>
      <link>https://lv-blog.pages.dev/posts/programming/%E7%90%86%E8%A7%A3mysql%E7%9A%84mvcc%E9%82%A3%E4%B9%88%E7%AE%80%E5%8D%95%E4%B8%BA%E4%BB%80%E4%B9%88%E5%B0%B1%E6%B2%A1%E6%9C%89%E4%BA%BA%E8%AF%B4%E4%BA%BA%E8%AF%9D/</link>
      <pubDate>Tue, 28 Jul 2026 13:40:09 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/%E7%90%86%E8%A7%A3mysql%E7%9A%84mvcc%E9%82%A3%E4%B9%88%E7%AE%80%E5%8D%95%E4%B8%BA%E4%BB%80%E4%B9%88%E5%B0%B1%E6%B2%A1%E6%9C%89%E4%BA%BA%E8%AF%B4%E4%BA%BA%E8%AF%9D/</guid>
      <description>&lt;ul&gt;
&lt;li&gt;我们为什么需要 MVCC ？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;没有MVCC（多版本并发控制 Multi-Version Concurrency Control）的情况下，面对数据库事务中&amp;quot;读某一条数据&amp;quot;的行为，我们只能加锁。这个锁可以是共享锁/排他锁，保证&amp;quot;我读的时候没人过来写&amp;quot;，避免脏读（读到和最终结果不一致的数据）。然而一旦加锁，其他线程就要等，一等并发效率就直线下降。&lt;/p&gt;
&lt;p&gt;MVCC 的思路是：读的时候不加锁，而是通过&amp;quot;版本&amp;quot;来判断一条数据对我来说能不能读。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每一行数据的三个隐藏字段ba&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每一条数据除了业务字段外，还有三个隐藏字段：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DB_TRX_ID   最近一次插入/更新/删除该行的事务id
DB_ROLL_PTR 回滚指针，指向这行数据在 undo log 中的上一个版本
DB_ROW_ID   隐藏主键，仅在表没有定义主键时才会生成
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;undo log 把同一行数据的历史版本串成一条链，DB_ROLL_PTR 就是链上的指针，出问题时可以顺着它一路往回找老版本。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read View：读之前先拍个快照&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在真正读数据之前，我们会先生成一个快照，叫做 read view。它记录了这几样东西：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;m_ids       生成快照那一刻，所有&amp;quot;活跃&amp;quot;（未提交）的事务id列表
min_trx_id  m_ids 里最小的那个id
max_trx_id  系统里下一个将要分配的事务id（也就是目前已知最大事务id + 1）
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意 max_trx_id 不是&amp;quot;当前活跃事务里最大的那个&amp;quot;，而是&amp;quot;还没被任何事务用过的、未来第一个可用的id&amp;quot;——因为事务id是全局递增分配的。&lt;/p&gt;
&lt;p&gt;这里要先说清楚一件容易被忽略的事：&lt;strong&gt;read view 什么时候生成，在不同隔离级别下是不一样的。&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;READ COMMITTED（读已提交）：每次执行 SELECT 语句都重新生成一个 read view
REPEATABLE READ（可重复读，MySQL默认）：只在事务内第一次执行 SELECT 时生成一次，之后整个事务复用同一个 read view
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个区别直接决定了&amp;quot;我这次读，能不能看到别人事务提交的新数据&amp;quot;——RC 每次都能看到最新提交的结果，RR 则始终锁定在事务开始时的那个快照上，这也是可重复读名字的由来。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;拿到 read view 之后，怎么判断某一行能不能读&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;现在回到最初的问题：我们要读一行数据，它的 DB_TRX_ID = 200。这条数据被事务200修改过，我们能不能读到它，要按顺序做以下判断：&lt;/p&gt;</description>
    </item>
    <item>
      <title>过家家项目：如何设计抢红包</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/%E5%A6%82%E4%BD%95%E8%AE%BE%E8%AE%A1%E6%8A%A2%E7%BA%A2%E5%8C%85/</link>
      <pubDate>Sat, 25 Jul 2026 11:09:53 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/%E5%A6%82%E4%BD%95%E8%AE%BE%E8%AE%A1%E6%8A%A2%E7%BA%A2%E5%8C%85/</guid>
      <description>&lt;p&gt;在我的项目“过家家”里，有一个抢红包的功能。功能类似微信抢红包。&lt;/p&gt;
&lt;h2 id=&#34;抢红包的基本逻辑&#34;&gt;抢红包的基本逻辑&lt;/h2&gt;
&lt;h3 id=&#34;v1低并发抢红包时实时使用二倍均值法计算只使用mysql&#34;&gt;v1（低并发）抢红包时实时使用二倍均值法计算，只使用MySQL&lt;/h3&gt;
&lt;h4 id=&#34;1-红包创建流程&#34;&gt;1. 红包创建流程&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;用户发红包时，指定总金额与红包个数&lt;/li&gt;
&lt;li&gt;系统将总金额拆分为指定数量的红包&lt;/li&gt;
&lt;li&gt;红包数量约束：
&lt;ul&gt;
&lt;li&gt;最少为 1 个&lt;/li&gt;
&lt;li&gt;最多不能超过群成员数量&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;2-红包金额分配策略&#34;&gt;2. 红包金额分配策略&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;单个红包&lt;/strong&gt;：不进行随机计算，抢到即获得全部金额&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多个红包&lt;/strong&gt;：采用二倍均值法进行随机分配
&lt;ul&gt;
&lt;li&gt;当前用户最大可抢金额 = 剩余金额 / 剩余人数 × 2&lt;/li&gt;
&lt;li&gt;实际可抢区间为 [0.01, 最大可抢金额 - 0.01]
&lt;ul&gt;
&lt;li&gt;下限 0.01 元：保证每个抢到的用户都有收益&lt;/li&gt;
&lt;li&gt;上限减 0.01 元：保证剩余红包仍有余额可抢&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;边际示例：10 元红包 2 人分，第 1 人可抢区间为 [0.01, 9.99]&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;3-数据持久化与防刷控制&#34;&gt;3. 数据持久化与防刷控制&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;红包创建后入库存储&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;发红包限流&lt;/strong&gt;：同一用户 10 秒内仅允许发送 1 个红包，防止手抖误操作&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;4-抢红包并发控制&#34;&gt;4. 抢红包并发控制&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;防重复抢&lt;/strong&gt;：在 &lt;code&gt;redpacket_grabs&lt;/code&gt; 表中建立 &lt;code&gt;(userId, redpacketId)&lt;/code&gt; 联合唯一索引，确保同一用户对同一红包仅能抢一次&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;防超卖&lt;/strong&gt;：采用数据库乐观锁机制
&lt;ul&gt;
&lt;li&gt;更新 &lt;code&gt;redpacket&lt;/code&gt; 表时，必须同时满足：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;remaining_count &amp;gt; 0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;remaining_amount &amp;gt;= 本次扣减金额&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;5-方法缺点&#34;&gt;5. 方法缺点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;每次请求直接打数据库，导致响应时间没有访问内存快&lt;/li&gt;
&lt;li&gt;每次请求都会使用二分均值法计算抢到的金额，并且做超卖判断，比较麻烦&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;v2-高并发红包创建好了就已经固定了抢红包的数量和个数加入redis&#34;&gt;v2 （高并发）红包创建好了就已经固定了抢红包的数量和个数，加入Redis&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;大致流程&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kafka 学习笔记</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/kafka-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</link>
      <pubDate>Sat, 18 Jul 2026 16:01:26 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/kafka-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</guid>
      <description>&lt;h2 id=&#34;偏移量索引&#34;&gt;偏移量索引&lt;/h2&gt;
&lt;h2 id=&#34;高可用&#34;&gt;高可用&lt;/h2&gt;
&lt;h2 id=&#34;isr机制&#34;&gt;ISR机制&lt;/h2&gt;</description>
    </item>
    <item>
      <title>DB MQ Redis 常见实践</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/db-mq-redis%E5%B8%B8%E8%A7%81%E5%AE%9E%E8%B7%B5/</link>
      <pubDate>Thu, 16 Jul 2026 22:20:21 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/db-mq-redis%E5%B8%B8%E8%A7%81%E5%AE%9E%E8%B7%B5/</guid>
      <description>&lt;h3 id=&#34;一读路径cache-aside旁路缓存&#34;&gt;一、读路径：Cache Aside(旁路缓存)&lt;/h3&gt;
&lt;p&gt;先查 Redis，命中就返回；未命中查 DB，回写 Redis 后返回。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Redis 三件套&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;问题&lt;/th&gt;
					&lt;th&gt;场景&lt;/th&gt;
					&lt;th&gt;解法&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;穿透&lt;/td&gt;
					&lt;td&gt;查一个&lt;strong&gt;不存在&lt;/strong&gt;的 key，每次都打到 DB&lt;/td&gt;
					&lt;td&gt;缓存空值(短 TTL) + 布隆过滤器 + 参数校验&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;击穿&lt;/td&gt;
					&lt;td&gt;某个&lt;strong&gt;热点 key 过期&lt;/strong&gt;，瞬间大量请求打到 DB&lt;/td&gt;
					&lt;td&gt;分布式锁只放一个线程回源 + 逻辑过期(异步重建) + 热点 key 不过期&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;雪崩&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;大批 key 同时过期&lt;/strong&gt;或 Redis 宕机&lt;/td&gt;
					&lt;td&gt;TTL 加随机抖动 + 多级缓存(Caffeine + Redis) + 熔断降级(Sentinel) + 集群/哨兵高可用&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;二写路径先写-db再删缓存&#34;&gt;二、写路径：先写 DB，再删缓存&lt;/h3&gt;
&lt;p&gt;不用&amp;quot;更新缓存&amp;quot;而用&amp;quot;删除缓存&amp;quot;：避免并发写导致的脏数据，也避免为不会被读的数据做无用计算(lazy loading)。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么是&amp;quot;先 DB 后删&amp;quot;而不是&amp;quot;先删后写 DB&amp;quot;？&lt;/strong&gt;
先删缓存，在写 DB 的间隙可能有读请求把&lt;strong&gt;旧值&lt;/strong&gt;重新加载进缓存，且这个旧值会一直存在直到过期。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;但先写后删仍有极小概率不一致&lt;/strong&gt;(读线程读到旧 DB 值 → 写线程写 DB + 删缓存 → 读线程回写旧值)。兜底方案：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Flutter 相关面试题整理</title>
      <link>https://lv-blog.pages.dev/posts/programming/frontend/flutter-interview-questions/</link>
      <pubDate>Wed, 15 Jul 2026 00:46:10 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/frontend/flutter-interview-questions/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;从互联网整理而来&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;一dart-基础&#34;&gt;一、Dart 基础&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Dart 的数据类型有哪些？&lt;/li&gt;
&lt;li&gt;var、final、const 的区别&lt;/li&gt;
&lt;li&gt;Dart 中 null safety 是什么，如何使用？&lt;/li&gt;
&lt;li&gt;late 关键字作用与使用场景&lt;/li&gt;
&lt;li&gt;Dart 函数可选参数、命名参数、位置参数区别&lt;/li&gt;
&lt;li&gt;箭头函数适用范围&lt;/li&gt;
&lt;li&gt;Dart 异步：Future、async/await 原理&lt;/li&gt;
&lt;li&gt;Stream 与 Future 区别，StreamController 使用&lt;/li&gt;
&lt;li&gt;sync*、async*、yield、yield each 作用&lt;/li&gt;
&lt;li&gt;Dart 类中 extends、implements、mixin 区别&lt;/li&gt;
&lt;li&gt;mixin 有什么限制，能否构造函数传参&lt;/li&gt;
&lt;li&gt;抽象类与接口区别&lt;/li&gt;
&lt;li&gt;泛型 T、?T、T?、required T 区别&lt;/li&gt;
&lt;li&gt;Dart 单例几种实现方式&lt;/li&gt;
&lt;li&gt;工厂构造函数 factory 作用&lt;/li&gt;
&lt;li&gt;常量构造函数使用条件&lt;/li&gt;
&lt;li&gt;级联运算符 .. 原理&lt;/li&gt;
&lt;li&gt;空值操作符 ?.、??、??= 用法&lt;/li&gt;
&lt;li&gt;Dart 枚举进阶用法，能否自定义属性方法&lt;/li&gt;
&lt;li&gt;Isolate 是什么，和线程区别，通信方式&lt;/li&gt;
&lt;li&gt;Isolate 共享内存吗，数据传递限制&lt;/li&gt;
&lt;li&gt;Zone 作用是什么&lt;/li&gt;
&lt;li&gt;Dart 垃圾回收机制&lt;/li&gt;
&lt;li&gt;函数一等公民体现在哪里&lt;/li&gt;
&lt;li&gt;typedef 作用与场景&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;二flutter-框架核心原理&#34;&gt;二、Flutter 框架核心原理&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Flutter 三棵树：Widget、Element、RenderTree 关系&lt;/li&gt;
&lt;li&gt;StatelessWidget 和 StatefulWidget 底层差异&lt;/li&gt;
&lt;li&gt;State 生命周期完整流程&lt;/li&gt;
&lt;li&gt;initState、didChangeDependencies、build、didUpdateWidget、dispose 执行时机&lt;/li&gt;
&lt;li&gt;setState 底层更新机制&lt;/li&gt;
&lt;li&gt;Widget 为什么是不可变的 immutable&lt;/li&gt;
&lt;li&gt;Element 作用，Element 复用逻辑&lt;/li&gt;
&lt;li&gt;RenderObject 职责是什么&lt;/li&gt;
&lt;li&gt;Key 的作用，几种 Key 区别（ValueKey、ObjectKey、UniqueKey、GlobalKey）&lt;/li&gt;
&lt;li&gt;GlobalKey 使用场景与隐患&lt;/li&gt;
&lt;li&gt;LocalKey 解决什么问题&lt;/li&gt;
&lt;li&gt;Widget 重建流程，哪些情况会触发重建&lt;/li&gt;
&lt;li&gt;什么是 const Widget，好处是什么&lt;/li&gt;
&lt;li&gt;Flutter 渲染流程：布局、绘制、合成步骤&lt;/li&gt;
&lt;li&gt;布局约束流程：Constraints 传递规则&lt;/li&gt;
&lt;li&gt;父布局约束如何限制子控件尺寸&lt;/li&gt;
&lt;li&gt;RepaintBoundary 作用，何时使用&lt;/li&gt;
&lt;li&gt;Layer 树作用，缓存机制&lt;/li&gt;
&lt;li&gt;Flutter 与原生 Android/iOS 渲染区别&lt;/li&gt;
&lt;li&gt;Skia 引擎作用&lt;/li&gt;
&lt;li&gt;Impeller 渲染引擎对比 Skia 优势&lt;/li&gt;
&lt;li&gt;Flutter 绘制原理，Canvas、Paint 流程&lt;/li&gt;
&lt;li&gt;PipelineOwner 作用&lt;/li&gt;
&lt;li&gt;WidgetsBinding、SchedulerBinding 职责&lt;/li&gt;
&lt;li&gt;帧调度流程：Vsync、帧回调执行顺序&lt;/li&gt;
&lt;li&gt;transientCallbacks、persistentCallbacks、postFrameCallbacks 区别&lt;/li&gt;
&lt;li&gt;Flutter 热重载原理，热重启区别&lt;/li&gt;
&lt;li&gt;编译模式：debug/profile/release 差异&lt;/li&gt;
&lt;li&gt;AOT、JIT 编译区别&lt;/li&gt;
&lt;li&gt;Flutter 页面路由底层实现原理&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;三布局--基础组件&#34;&gt;三、布局 &amp;amp; 基础组件&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Row Column Flex 布局区别，主轴交叉轴概念&lt;/li&gt;
&lt;li&gt;MainAxisAlignment、CrossAxisAlignment 所有枚举值含义&lt;/li&gt;
&lt;li&gt;Expanded、Flexible 区别，flex 参数作用&lt;/li&gt;
&lt;li&gt;Stack、Positioned 布局规则&lt;/li&gt;
&lt;li&gt;Align、Center 底层关系&lt;/li&gt;
&lt;li&gt;Padding、Container 内部结构&lt;/li&gt;
&lt;li&gt;Container 嵌套过多有什么性能问题&lt;/li&gt;
&lt;li&gt;SizedBox、ConstrainedBox、UnconstrainedBox 用途&lt;/li&gt;
&lt;li&gt;AspectRatio、FittedBox 缩放逻辑&lt;/li&gt;
&lt;li&gt;Wrap 自动换行实现原理&lt;/li&gt;
&lt;li&gt;ListView 几种构造方式区别（默认、builder、separated）&lt;/li&gt;
&lt;li&gt;ListView.builder 高性能原理，复用机制&lt;/li&gt;
&lt;li&gt;ListView 滚动复用失效场景&lt;/li&gt;
&lt;li&gt;GridView 使用与性能优化&lt;/li&gt;
&lt;li&gt;SingleChildScrollView 嵌套 ListView 报错解决方案&lt;/li&gt;
&lt;li&gt;CustomScrollView、Sliver 体系是什么&lt;/li&gt;
&lt;li&gt;SliverList、SliverGrid、SliverAppBar、SliverToBoxAdapter 使用场景&lt;/li&gt;
&lt;li&gt;SliverPersistentHeader 固定吸顶实现&lt;/li&gt;
&lt;li&gt;CustomScrollView 滚动统一原理&lt;/li&gt;
&lt;li&gt;Table、DataTable 布局特性&lt;/li&gt;
&lt;li&gt;IntrinsicHeight、IntrinsicWidth 性能损耗原因&lt;/li&gt;
&lt;li&gt;LayoutBuilder 获取父布局约束场景&lt;/li&gt;
&lt;li&gt;MediaQuery 获取设备信息，MediaQuery.of(context) 刷新机制&lt;/li&gt;
&lt;li&gt;LayoutId、MultiChildLayout 自定义布局&lt;/li&gt;
&lt;li&gt;Flow 高性能流式布局适用场景&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;四状态管理&#34;&gt;四、状态管理&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;State 自身状态管理优缺点&lt;/li&gt;
&lt;li&gt;InheritedWidget 底层原理，数据传递逻辑&lt;/li&gt;
&lt;li&gt;InheritedModel 对比 InheritedWidget 优势&lt;/li&gt;
&lt;li&gt;Provider 整套库实现原理（ChangeNotifierProvider、Consumer、Selector）&lt;/li&gt;
&lt;li&gt;Selector 为什么能精准局部刷新&lt;/li&gt;
&lt;li&gt;ChangeNotifier 通知更新机制&lt;/li&gt;
&lt;li&gt;StateProvider、FutureProvider、StreamProvider 区别&lt;/li&gt;
&lt;li&gt;Riverpod 对比 Provider 改进点&lt;/li&gt;
&lt;li&gt;Riverpod 全局状态、自动 dispose、无 context 优势&lt;/li&gt;
&lt;li&gt;StateNotifier、AsyncNotifier 使用场景&lt;/li&gt;
&lt;li&gt;Bloc 核心概念：Event、State、Bloc/Cubit&lt;/li&gt;
&lt;li&gt;Cubit 与 Bloc 区别&lt;/li&gt;
&lt;li&gt;BlocProvider、BlocConsumer、BlocBuilder、BlocListener 分工&lt;/li&gt;
&lt;li&gt;Bloc 状态单一数据源优势&lt;/li&gt;
&lt;li&gt;GetX 状态管理原理，GetController 生命周期&lt;/li&gt;
&lt;li&gt;GetX 全局路由、依赖注入实现&lt;/li&gt;
&lt;li&gt;GetX 优缺点，存在什么性能隐患&lt;/li&gt;
&lt;li&gt;Redux 在 Flutter 中使用逻辑&lt;/li&gt;
&lt;li&gt;MobX 响应式原理，Observable、Action、Reaction&lt;/li&gt;
&lt;li&gt;大型项目如何选型状态管理方案&lt;/li&gt;
&lt;li&gt;跨页面共享状态几种实现方式对比&lt;/li&gt;
&lt;li&gt;状态持久化配合状态管理怎么做&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;五路由--导航&#34;&gt;五、路由 &amp;amp; 导航&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Navigator 1.0 路由栈管理原理&lt;/li&gt;
&lt;li&gt;MaterialPageRoute、CupertinoPageRoute 区别&lt;/li&gt;
&lt;li&gt;PageRouteBuilder 自定义转场动画&lt;/li&gt;
&lt;li&gt;Navigator push/pop/pushReplacement/popUntil 逻辑&lt;/li&gt;
&lt;li&gt;路由传参几种方式&lt;/li&gt;
&lt;li&gt;Navigator 2.0 核心组件：Router、RouteInformationParser、RouterDelegate&lt;/li&gt;
&lt;li&gt;Navigator 2.0 完整路由流程&lt;/li&gt;
&lt;li&gt;GoRouter 框架底层封装逻辑&lt;/li&gt;
&lt;li&gt;GoRouter 嵌套路由、路由守卫、参数获取&lt;/li&gt;
&lt;li&gt;路由栈持久化、页面状态保存方案&lt;/li&gt;
&lt;li&gt;底部导航多 Tab 页面状态保持实现&lt;/li&gt;
&lt;li&gt;路由拦截、登录鉴权统一处理&lt;/li&gt;
&lt;li&gt;原生页面与 Flutter 页面互相跳转路由处理&lt;/li&gt;
&lt;li&gt;页面返回监听 WillPopScope、PopScope&lt;/li&gt;
&lt;li&gt;深度链接 deep link 适配方案&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;六动画&#34;&gt;六、动画&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Flutter 动画核心类：Animation、AnimationController、CurvedAnimation&lt;/li&gt;
&lt;li&gt;AnimationController vsync 作用，为什么需要 TickerProvider&lt;/li&gt;
&lt;li&gt;SingleTickerProviderStateMixin、TickerProviderStateMixin 区别&lt;/li&gt;
&lt;li&gt;Tween、Animatable 差值计算原理&lt;/li&gt;
&lt;li&gt;显式动画与隐式动画区别&lt;/li&gt;
&lt;li&gt;AnimatedContainer、AnimatedOpacity 等隐式动画底层&lt;/li&gt;
&lt;li&gt;Hero 共享元素动画实现原理&lt;/li&gt;
&lt;li&gt;PageRoute 共享 Hero 流程&lt;/li&gt;
&lt;li&gt;CustomAnimation 自定义动画组件&lt;/li&gt;
&lt;li&gt;交错动画 Interval 使用&lt;/li&gt;
&lt;li&gt;动画性能优化，避免重建&lt;/li&gt;
&lt;li&gt;Lottie 动画集成原理，性能注意点&lt;/li&gt;
&lt;li&gt;循环动画、反向动画实现&lt;/li&gt;
&lt;li&gt;动画暂停、恢复、释放资源处理&lt;/li&gt;
&lt;li&gt;自定义路由转场动画&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;七网络--本地存储&#34;&gt;七、网络 &amp;amp; 本地存储&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;dio 库封装思路，拦截器使用&lt;/li&gt;
&lt;li&gt;dio 统一请求头、错误处理、token 自动刷新&lt;/li&gt;
&lt;li&gt;取消请求 CancelToken 使用场景&lt;/li&gt;
&lt;li&gt;并发请求、超时处理&lt;/li&gt;
&lt;li&gt;Json 序列化反序列化几种方式（手动、json_serializable）&lt;/li&gt;
&lt;li&gt;fromJson/toJson 生成流程&lt;/li&gt;
&lt;li&gt;Freezed 数据模型优势&lt;/li&gt;
&lt;li&gt;http 库与 dio 对比&lt;/li&gt;
&lt;li&gt;WebSocket 在 Flutter 中使用，重连机制&lt;/li&gt;
&lt;li&gt;shared_preferences 底层存储原理&lt;/li&gt;
&lt;li&gt;Hive 本地数据库优势，Box 使用&lt;/li&gt;
&lt;li&gt;Hive 加密、大数据存储优化&lt;/li&gt;
&lt;li&gt;sqflite 数据库操作，事务使用&lt;/li&gt;
&lt;li&gt;Isolate 中操作数据库注意事项&lt;/li&gt;
&lt;li&gt;文件读写 path_provider 获取路径&lt;/li&gt;
&lt;li&gt;图片缓存 cached_network_image 实现逻辑&lt;/li&gt;
&lt;li&gt;网络请求缓存策略设计&lt;/li&gt;
&lt;li&gt;接口统一异常捕获封装方案&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;八原生交互-methodchannel&#34;&gt;八、原生交互 MethodChannel&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;MethodChannel、BasicMessageChannel、EventChannel 三者区别&lt;/li&gt;
&lt;li&gt;MethodChannel 双向通信完整流程&lt;/li&gt;
&lt;li&gt;Flutter 调用 Android 原生代码步骤&lt;/li&gt;
&lt;li&gt;Flutter 调用 iOS OC/Swift 步骤&lt;/li&gt;
&lt;li&gt;原生主动推送数据给 Flutter 使用哪个 Channel&lt;/li&gt;
&lt;li&gt;传参类型限制，复杂对象传递方案&lt;/li&gt;
&lt;li&gt;多页面 Channel 单例管理&lt;/li&gt;
&lt;li&gt;PlatformView 嵌入原生 View（Android View、iOS UIView）&lt;/li&gt;
&lt;li&gt;PlatformView 性能问题与优化&lt;/li&gt;
&lt;li&gt;原生页面跳转 Flutter 传参&lt;/li&gt;
&lt;li&gt;权限通过原生通道申请方案&lt;/li&gt;
&lt;li&gt;混合栈开发：flutterBoost 原理&lt;/li&gt;
&lt;li&gt;flutterBoost 页面生命周期同步问题&lt;/li&gt;
&lt;li&gt;原生资源与 Flutter 资源冲突处理&lt;/li&gt;
&lt;li&gt;通信通道内存泄漏如何避免&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;九性能优化专项&#34;&gt;九、性能优化专项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Widget 重建常见诱因与规避手段&lt;/li&gt;
&lt;li&gt;const 构造优化原理&lt;/li&gt;
&lt;li&gt;Key 不合理使用导致的性能问题&lt;/li&gt;
&lt;li&gt;ListView 长列表优化方案&lt;/li&gt;
&lt;li&gt;图片加载优化：尺寸、缓存、压缩&lt;/li&gt;
&lt;li&gt;RepaintBoundary 拆分重绘区域场景&lt;/li&gt;
&lt;li&gt;减少 Layer 树层级优化&lt;/li&gt;
&lt;li&gt;避免使用 Intrinsic 系列控件原因&lt;/li&gt;
&lt;li&gt;动画卡顿排查思路&lt;/li&gt;
&lt;li&gt;DevTools 工具使用：性能面板、内存、Widget 检查&lt;/li&gt;
&lt;li&gt;内存泄漏常见场景（Timer、Stream、Channel、Animation）&lt;/li&gt;
&lt;li&gt;大图片、大量对象内存释放方案&lt;/li&gt;
&lt;li&gt;Isolate 处理耗时计算优化 UI&lt;/li&gt;
&lt;li&gt;build 方法避免耗时操作&lt;/li&gt;
&lt;li&gt;布局嵌套过深优化手段&lt;/li&gt;
&lt;li&gt;页面 dispose 资源释放规范&lt;/li&gt;
&lt;li&gt;Profile 模式性能排查要点&lt;/li&gt;
&lt;li&gt;启动速度优化（包体积、懒加载、预加载）&lt;/li&gt;
&lt;li&gt;Flutter 包体积优化方案&lt;/li&gt;
&lt;li&gt;滑动卡顿完整排查流程&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十图片手势输入弹窗组件&#34;&gt;十、图片、手势、输入、弹窗组件&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Image 几种构造：AssetImage、NetworkImage、FileImage、MemoryImage&lt;/li&gt;
&lt;li&gt;ImageProvider 缓存机制&lt;/li&gt;
&lt;li&gt;Image.network 缓存缺陷，cached_network_image 弥补方案&lt;/li&gt;
&lt;li&gt;DecorationImage、FadeInImage 使用&lt;/li&gt;
&lt;li&gt;GestureDetector 手势识别原理，多手势冲突&lt;/li&gt;
&lt;li&gt;Listener 底层原始手势与 GestureDetector 区别&lt;/li&gt;
&lt;li&gt;手势竞争、手势忽略场景&lt;/li&gt;
&lt;li&gt;InkWell 水波纹实现原理，必须嵌套 Material&lt;/li&gt;
&lt;li&gt;TextField 控制器 TextEditingController 使用&lt;/li&gt;
&lt;li&gt;TextField 输入监听、格式化、光标控制&lt;/li&gt;
&lt;li&gt;表单 Form、GlobalKey&lt;FormState&gt; 校验逻辑&lt;/li&gt;
&lt;li&gt;ModalRoute、showDialog、showBottomSheet 弹窗原理&lt;/li&gt;
&lt;li&gt;弹窗状态共享问题解决方案&lt;/li&gt;
&lt;li&gt;Draggable、LongPressDraggable 拖拽实现&lt;/li&gt;
&lt;li&gt;Transform 变换不改变布局约束特性&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十一项目工程--打包适配&#34;&gt;十一、项目工程 &amp;amp; 打包适配&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;pubspec.yaml 各字段含义，依赖版本约束&lt;/li&gt;
&lt;li&gt;本地依赖、Git 依赖、远程依赖配置&lt;/li&gt;
&lt;li&gt;pub 依赖冲突解决方法&lt;/li&gt;
&lt;li&gt;Flutter 多环境配置（开发/测试/生产）&lt;/li&gt;
&lt;li&gt;Flavor 多渠道打包 Android &amp;amp; iOS&lt;/li&gt;
&lt;li&gt;Android 打包 keystore 配置，iOS 证书配置&lt;/li&gt;
&lt;li&gt;AndroidManifest、Info.plist 权限适配&lt;/li&gt;
&lt;li&gt;屏幕适配方案：媒体查询、比例、flutter_screenutil&lt;/li&gt;
&lt;li&gt;深色模式适配实现&lt;/li&gt;
&lt;li&gt;多语言国际化 intl 库使用&lt;/li&gt;
&lt;li&gt;App 图标、启动页配置&lt;/li&gt;
&lt;li&gt;Flutter 插件开发流程&lt;/li&gt;
&lt;li&gt;平台区分代码编写（dart.io、Platform 判断）&lt;/li&gt;
&lt;li&gt;混合开发项目目录结构&lt;/li&gt;
&lt;li&gt;CI/CD 自动打包脚本思路&lt;/li&gt;
&lt;li&gt;版本号管理升级方案&lt;/li&gt;
&lt;li&gt;第三方插件兼容问题处理&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十二进阶底层--疑难场景&#34;&gt;十二、进阶底层 &amp;amp; 疑难场景&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;WidgetsApp、MaterialApp、CupertinoApp 内部结构&lt;/li&gt;
&lt;li&gt;ThemeData 主题分发原理，局部主题覆盖&lt;/li&gt;
&lt;li&gt;Navigator 上下文与页面上下文区别&lt;/li&gt;
&lt;li&gt;context 获取上层 Widget 原理，BuildContext 分类&lt;/li&gt;
&lt;li&gt;State 保存在 Element 中，Widget 重建 State 不销毁条件&lt;/li&gt;
&lt;li&gt;Offstage、Visibility 控件隐藏区别&lt;/li&gt;
&lt;li&gt;AbsorbPointer、IgnorePointer 拦截手势差异&lt;/li&gt;
&lt;li&gt;Clip 裁剪控件：ClipRect、ClipRRect、ClipOval 性能&lt;/li&gt;
&lt;li&gt;BackdropFilter 模糊控件性能损耗原因&lt;/li&gt;
&lt;li&gt;RenderBox 自定义控件完整流程&lt;/li&gt;
&lt;li&gt;自定义 RenderObject 实现步骤&lt;/li&gt;
&lt;li&gt;自定义 MultiChildRenderObjectWidget&lt;/li&gt;
&lt;li&gt;ScrollController 监听滚动、滚动定位&lt;/li&gt;
&lt;li&gt;ScrollPhysics 滚动回弹、阻尼自定义&lt;/li&gt;
&lt;li&gt;监听应用前后台切换 AppLifecycleState&lt;/li&gt;
&lt;li&gt;截屏、屏幕亮度、震动原生能力实现&lt;/li&gt;
&lt;li&gt;WebView 插件使用与通信&lt;/li&gt;
&lt;li&gt;Flutter Web 编译差异，平台兼容问题&lt;/li&gt;
&lt;li&gt;Flutter Windows/macOS/Linux 桌面端适配要点&lt;/li&gt;
&lt;li&gt;如何实现全局捕获异常&lt;/li&gt;
&lt;li&gt;Timer、StreamSubscription 忘记取消的内存泄漏&lt;/li&gt;
&lt;li&gt;列表 item 点击状态保存方案&lt;/li&gt;
&lt;li&gt;异步并发竞态条件问题处理&lt;/li&gt;
&lt;li&gt;图片大量加载 OOM 解决方案&lt;/li&gt;
&lt;li&gt;原生弹窗遮挡 Flutter 页面问题&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十三综合项目面试问答题&#34;&gt;十三、综合项目面试问答题&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;讲一下你项目整体架构分层&lt;/li&gt;
&lt;li&gt;项目状态管理选型原因&lt;/li&gt;
&lt;li&gt;长列表卡顿怎么优化的&lt;/li&gt;
&lt;li&gt;多页面共享登录状态如何实现&lt;/li&gt;
&lt;li&gt;token 过期统一拦截处理方案&lt;/li&gt;
&lt;li&gt;项目混合栈开发遇到哪些坑&lt;/li&gt;
&lt;li&gt;图片缓存、网络缓存怎么设计&lt;/li&gt;
&lt;li&gt;全局网络加载弹窗、错误页封装思路&lt;/li&gt;
&lt;li&gt;项目通用业务组件封装思路&lt;/li&gt;
&lt;li&gt;线上卡顿、崩溃排查处理经验&lt;/li&gt;
&lt;li&gt;如何实现页面无网络重试逻辑&lt;/li&gt;
&lt;li&gt;复杂表单页面状态管理方案&lt;/li&gt;
&lt;li&gt;项目包体积优化做了哪些操作&lt;/li&gt;
&lt;li&gt;多渠道、多环境配置实现&lt;/li&gt;
&lt;li&gt;封装通用 Dio 请求库完整思路&lt;/li&gt;
&lt;/ol&gt;</description>
    </item>
    <item>
      <title>MyBatis 相关面试题整理</title>
      <link>https://lv-blog.pages.dev/posts/programming/for-interview/mybatis-interview-questions/</link>
      <pubDate>Wed, 15 Jul 2026 00:46:10 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/for-interview/mybatis-interview-questions/</guid>
      <description>&lt;h2 id=&#34;mybatis-执行流程&#34;&gt;Mybatis 执行流程&lt;/h2&gt;
&lt;p&gt;mybatis-config.xml (总规)
↓
SqlSessionFactory (总管)
↓
SqlSession (服务员) —— 包含所有执行方法
↓
Executor (大管家) —— 优先查缓存（一级/二级）
↓
MappedStatement (菜谱) —— 持有SQL、参数映射、结果映射
↓
输入参数映射 (备菜) → JDBC执行 → 输出结果映射 (装盘)
↓
返回POJO/集合 (上菜)&lt;/p&gt;
&lt;h2 id=&#34;mybatis-是否支持延迟加载&#34;&gt;Mybatis 是否支持延迟加载&lt;/h2&gt;
&lt;p&gt;支持，默认不开启&lt;/p&gt;
&lt;p&gt;collection fecthType=&amp;ldquo;lazy&amp;rdquo;&lt;/p&gt;
&lt;p&gt;mybatis配置文件延迟加载 lazyLoadingEnabled&lt;/p&gt;
&lt;p&gt;延迟加载的原理&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;CGLIB创建目标对象的代理对象&lt;/li&gt;
&lt;li&gt;调用目标方法 getOrderList&lt;/li&gt;
&lt;li&gt;调用对象 invoke 方法&lt;/li&gt;
&lt;li&gt;判断 orderList 是否为空&lt;/li&gt;
&lt;li&gt;为空，执行SQL&lt;/li&gt;
&lt;li&gt;不为空获取结果&lt;/li&gt;
&lt;li&gt;封装 orderList&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;mybatis-的一级缓存-二级缓存-用过吗&#34;&gt;Mybatis 的一级缓存 二级缓存 用过吗&lt;/h2&gt;
&lt;p&gt;本地缓存 - 基于 PerpetualCache 本质是一个 HashMap
一级缓存 - 作用域是 session 级别
二级缓存 - 作用域是namespace 和 mapper的作用域，不依赖于 session
二级缓存默认关闭
settings name=&amp;ldquo;cacheEnabled&amp;rdquo; value=&amp;ldquo;true&amp;rdquo;
当某个作用域进行了增删改操作，该作用域下的所有select的缓存将被clear&lt;/p&gt;</description>
    </item>
    <item>
      <title>React 相关面试题整理</title>
      <link>https://lv-blog.pages.dev/posts/programming/frontend/react-interview-questions/</link>
      <pubDate>Wed, 15 Jul 2026 00:46:10 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/frontend/react-interview-questions/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;从互联网整理而来&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;一js-基础前置&#34;&gt;一、JS 基础前置&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;原型与原型链&lt;/li&gt;
&lt;li&gt;闭包、闭包引发的内存泄漏场景&lt;/li&gt;
&lt;li&gt;同步异步、宏任务微任务执行顺序&lt;/li&gt;
&lt;li&gt;Promise 状态、静态方法、链式调用&lt;/li&gt;
&lt;li&gt;async/await 原理&lt;/li&gt;
&lt;li&gt;深浅拷贝实现与区别&lt;/li&gt;
&lt;li&gt;this 指向五种场景&lt;/li&gt;
&lt;li&gt;箭头函数与普通函数差异&lt;/li&gt;
&lt;li&gt;ES6 解构、展开运算符、剩余参数&lt;/li&gt;
&lt;li&gt;var / let / const 区别&lt;/li&gt;
&lt;li&gt;CommonJS 与 ES Module 差异&lt;/li&gt;
&lt;li&gt;TypeScript 接口、泛型、交叉类型、联合类型&lt;/li&gt;
&lt;li&gt;EventLoop 完整执行流程&lt;/li&gt;
&lt;li&gt;防抖节流实现原理&lt;/li&gt;
&lt;li&gt;纯函数定义与特性&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;二react-基础核心概念&#34;&gt;二、React 基础核心概念&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;React 设计思想与核心理念&lt;/li&gt;
&lt;li&gt;虚拟 DOM 是什么，作用与优势&lt;/li&gt;
&lt;li&gt;JSX 语法本质，编译产物&lt;/li&gt;
&lt;li&gt;JSX 中 {} 可放入哪些内容，不能放什么&lt;/li&gt;
&lt;li&gt;React 元素与组件区别&lt;/li&gt;
&lt;li&gt;函数组件与类组件区别&lt;/li&gt;
&lt;li&gt;纯组件 PureComponent 原理&lt;/li&gt;
&lt;li&gt;React 单向数据流含义&lt;/li&gt;
&lt;li&gt;props 只读特性，为什么不能直接修改&lt;/li&gt;
&lt;li&gt;props.children 有哪些类型&lt;/li&gt;
&lt;li&gt;key 的作用，为什么不能用 index 做 key&lt;/li&gt;
&lt;li&gt;React 列表渲染注意事项&lt;/li&gt;
&lt;li&gt;className 代替 class、htmlFor 代替 for 原因&lt;/li&gt;
&lt;li&gt;React 事件绑定与原生 DOM 事件差异&lt;/li&gt;
&lt;li&gt;合成事件原理、事件委托机制&lt;/li&gt;
&lt;li&gt;阻止合成事件冒泡几种方式&lt;/li&gt;
&lt;li&gt;dangerouslySetInnerHTML 使用场景与风险&lt;/li&gt;
&lt;li&gt;React 为什么不直接操作 DOM&lt;/li&gt;
&lt;li&gt;Fragment 作用，短语法 &amp;lt;&amp;gt;&lt;/li&gt;
&lt;li&gt;React 严格模式 StrictMode 作用&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;三类组件生命周期class-component&#34;&gt;三、类组件生命周期（Class Component）&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;类组件完整生命周期分哪三个阶段&lt;/li&gt;
&lt;li&gt;constructor 执行时机与作用&lt;/li&gt;
&lt;li&gt;static getDerivedStateFromProps 执行时机与用途&lt;/li&gt;
&lt;li&gt;shouldComponentUpdate 返回值作用&lt;/li&gt;
&lt;li&gt;render 执行规则，禁止在其中修改 state&lt;/li&gt;
&lt;li&gt;componentDidMount 执行时机、常用场景&lt;/li&gt;
&lt;li&gt;getSnapshotBeforeUpdate 触发时机、返回值用途&lt;/li&gt;
&lt;li&gt;componentDidUpdate 参数含义，依赖判断写法&lt;/li&gt;
&lt;li&gt;componentWillUnmount 清理资源场景&lt;/li&gt;
&lt;li&gt;废弃生命周期函数有哪些，为什么废弃&lt;/li&gt;
&lt;li&gt;props 变化触发的生命周期流程&lt;/li&gt;
&lt;li&gt;setState 同步还是异步，底层批量更新逻辑&lt;/li&gt;
&lt;li&gt;setState 两种传参形式（对象/函数）区别&lt;/li&gt;
&lt;li&gt;多次连续 setState 合并规则&lt;/li&gt;
&lt;li&gt;如何在 setState 后拿到最新 state&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;四hooks-全套react168&#34;&gt;四、Hooks 全套（React16.8+）&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Hook 诞生背景，解决类组件什么痛点&lt;/li&gt;
&lt;li&gt;Hook 使用两条硬性规则&lt;/li&gt;
&lt;li&gt;useState 底层原理，为何数组解构不受顺序影响&lt;/li&gt;
&lt;li&gt;useState 传入函数初始化的优势&lt;/li&gt;
&lt;li&gt;useEffect 作用，依赖数组含义&lt;/li&gt;
&lt;li&gt;useEffect 模拟生命周期分别怎么写&lt;/li&gt;
&lt;li&gt;useEffect 返回清理函数执行时机&lt;/li&gt;
&lt;li&gt;依赖数组漏传变量引发的闭包陷阱&lt;/li&gt;
&lt;li&gt;useLayoutEffect 和 useEffect 执行顺序、区别&lt;/li&gt;
&lt;li&gt;useMemo 缓存计算值，解决什么问题&lt;/li&gt;
&lt;li&gt;useCallback 缓存函数，搭配子组件使用场景&lt;/li&gt;
&lt;li&gt;useMemo 与 useCallback 性能误区&lt;/li&gt;
&lt;li&gt;useRef 存储DOM、存储可变数据两种用法&lt;/li&gt;
&lt;li&gt;ref 传递 forwardRef 使用场景&lt;/li&gt;
&lt;li&gt;useImperativeHandle 作用&lt;/li&gt;
&lt;li&gt;useContext 跨层级传值，使用缺陷&lt;/li&gt;
&lt;li&gt;useReducer 适用场景，和 useState 对比&lt;/li&gt;
&lt;li&gt;useReducer 简单实现思路&lt;/li&gt;
&lt;li&gt;useId 作用，解决什么问题&lt;/li&gt;
&lt;li&gt;useTransition 区分紧急/非紧急更新&lt;/li&gt;
&lt;li&gt;useDeferredValue 延迟计算值&lt;/li&gt;
&lt;li&gt;useSyncExternalStore 订阅外部数据源&lt;/li&gt;
&lt;li&gt;useDebugValue 自定义Hook调试展示&lt;/li&gt;
&lt;li&gt;自定义 Hook 封装规范，复用逻辑思路&lt;/li&gt;
&lt;li&gt;Hook 闭包陷阱完整成因与解决方案&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;五react18-新特性&#34;&gt;五、React18 新特性&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;React18 并发渲染 Concurrent Mode 含义&lt;/li&gt;
&lt;li&gt;自动批处理更新范围变化&lt;/li&gt;
&lt;li&gt;createRoot 替换 legacy root 差异&lt;/li&gt;
&lt;li&gt;Suspense 服务端/客户端用法&lt;/li&gt;
&lt;li&gt;Transitions API 解决场景&lt;/li&gt;
&lt;li&gt;自动插入批处理，异步回调内也合并更新&lt;/li&gt;
&lt;li&gt;useTransition 与 useDeferredValue 区别&lt;/li&gt;
&lt;li&gt;服务端组件 RSC 基础概念&lt;/li&gt;
&lt;li&gt;StrictMode 双重渲染机制目的&lt;/li&gt;
&lt;li&gt;批量更新边界，何时不会合并state更新&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;六diff-算法与渲染更新&#34;&gt;六、Diff 算法与渲染更新&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;React Diff 三大策略&lt;/li&gt;
&lt;li&gt;同层比较，不跨层级对比原因&lt;/li&gt;
&lt;li&gt;无key、index key、唯一key三种场景对比&lt;/li&gt;
&lt;li&gt;节点删除、新增、移动判断逻辑&lt;/li&gt;
&lt;li&gt;文本节点、组件节点 Diff 区别&lt;/li&gt;
&lt;li&gt;列表 Diff 优化逻辑&lt;/li&gt;
&lt;li&gt;什么情况下组件会重新渲染&lt;/li&gt;
&lt;li&gt;如何避免不必要的重渲染&lt;/li&gt;
&lt;li&gt;memo、useMemo、useCallback 配合使用完整逻辑&lt;/li&gt;
&lt;li&gt;渲染流程：render → 生成VNode → Diff → 真实DOM更新&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;七组件通信方案&#34;&gt;七、组件通信方案&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;父子组件 props 传值、回调传方法&lt;/li&gt;
&lt;li&gt;多层级透传 props 缺点&lt;/li&gt;
&lt;li&gt;Context API 跨层级通信优缺点&lt;/li&gt;
&lt;li&gt;Context 配合 useReducer 简易状态管理&lt;/li&gt;
&lt;li&gt;父访问子组件实例 ref&lt;/li&gt;
&lt;li&gt;子调用父方法回调函数&lt;/li&gt;
&lt;li&gt;兄弟组件通信几种方案&lt;/li&gt;
&lt;li&gt;全局事件总线实现与缺陷&lt;/li&gt;
&lt;li&gt;跨页面全局状态管理方案对比&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;八状态管理-redux--redux-toolkit--zustand&#34;&gt;八、状态管理 Redux / Redux Toolkit / Zustand&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Redux 三大核心原则&lt;/li&gt;
&lt;li&gt;Redux 五大核心概念：Store、Action、Reducer、Dispatch、State&lt;/li&gt;
&lt;li&gt;Reducer 必须纯函数要求&lt;/li&gt;
&lt;li&gt;Action plain object 规范，为什么不能异步&lt;/li&gt;
&lt;li&gt;中间件 middleware 作用，执行流程&lt;/li&gt;
&lt;li&gt;redux-thunk 异步处理原理&lt;/li&gt;
&lt;li&gt;redux-saga 对比 thunk 优势&lt;/li&gt;
&lt;li&gt;combineReducers 拆分模块原理&lt;/li&gt;
&lt;li&gt;react-redux 核心 API Provider、connect&lt;/li&gt;
&lt;li&gt;mapStateToProps、mapDispatchToProps 作用&lt;/li&gt;
&lt;li&gt;useSelector、useDispatch Hook 用法&lt;/li&gt;
&lt;li&gt;Redux 数据单向流动完整流程&lt;/li&gt;
&lt;li&gt;Redux Toolkit 解决原生Redux哪些痛点&lt;/li&gt;
&lt;li&gt;createSlice 内置 reducer、action 生成&lt;/li&gt;
&lt;li&gt;RTK 内置immer 实现可变写法原理&lt;/li&gt;
&lt;li&gt;RTK Query 接口缓存、请求管理&lt;/li&gt;
&lt;li&gt;Zustand 轻量状态库对比Redux优势&lt;/li&gt;
&lt;li&gt;状态持久化 redux-persist 流程&lt;/li&gt;
&lt;li&gt;大型项目状态库选型思路&lt;/li&gt;
&lt;li&gt;多组件共享全局状态最佳实践&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;九react-router-v6&#34;&gt;九、React Router v6&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;v5 与 v6 核心改动差异&lt;/li&gt;
&lt;li&gt;createBrowserRouter 路由配置方式&lt;/li&gt;
&lt;li&gt;BrowserRouter、HashRouter、MemoryRouter 区别&lt;/li&gt;
&lt;li&gt;Routes 替代 Switch 作用&lt;/li&gt;
&lt;li&gt;Route element 传组件写法&lt;/li&gt;
&lt;li&gt;useNavigate 替代 useHistory&lt;/li&gt;
&lt;li&gt;路由传参 params、search、state 三种方式&lt;/li&gt;
&lt;li&gt;useParams、useSearchParams 使用&lt;/li&gt;
&lt;li&gt;嵌套路由 Outlet 占位原理&lt;/li&gt;
&lt;li&gt;index 索引路由作用&lt;/li&gt;
&lt;li&gt;Link、NavLink 区别&lt;/li&gt;
&lt;li&gt;路由守卫鉴权封装方案&lt;/li&gt;
&lt;li&gt;路由懒加载 + Suspense 配置&lt;/li&gt;
&lt;li&gt;useLocation 获取路由信息&lt;/li&gt;
&lt;li&gt;动态路由、路由拦截封装&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十表单处理&#34;&gt;十、表单处理&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;受控组件与非受控组件定义、区别&lt;/li&gt;
&lt;li&gt;受控组件完整实现思路&lt;/li&gt;
&lt;li&gt;非受控组件通过 ref 获取值场景&lt;/li&gt;
&lt;li&gt;多表单项统一封装受控逻辑&lt;/li&gt;
&lt;li&gt;第三方表单库 Formik / React Hook Form 对比&lt;/li&gt;
&lt;li&gt;React Hook Form 非受控高性能原理&lt;/li&gt;
&lt;li&gt;表单校验方案：原生、yup、zod&lt;/li&gt;
&lt;li&gt;表单批量重置、回填数据处理&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十一样式方案&#34;&gt;十一、样式方案&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;inline 内联样式优缺点&lt;/li&gt;
&lt;li&gt;CSS Modules 样式隔离原理&lt;/li&gt;
&lt;li&gt;styled-components CSS-in-JS 原理&lt;/li&gt;
&lt;li&gt;emotion 与 styled-components 对比&lt;/li&gt;
&lt;li&gt;tailwindcss 在React项目使用优势&lt;/li&gt;
&lt;li&gt;动态样式几种实现方式&lt;/li&gt;
&lt;li&gt;全局样式污染解决方案&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十二工程化构建&#34;&gt;十二、工程化构建&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Create React App 底层 webpack 配置&lt;/li&gt;
&lt;li&gt;Vite 构建React项目优势，esbuild预构建&lt;/li&gt;
&lt;li&gt;vite.config.js 常用配置项&lt;/li&gt;
&lt;li&gt;webpack 处理jsx、ts-loader流程&lt;/li&gt;
&lt;li&gt;babel 转换 JSX、polyfill 原理&lt;/li&gt;
&lt;li&gt;.env 环境变量区分开发/测试/生产&lt;/li&gt;
&lt;li&gt;跨域代理 proxy 配置&lt;/li&gt;
&lt;li&gt;路由懒加载分包代码分割&lt;/li&gt;
&lt;li&gt;Tree-Shaking 生效条件&lt;/li&gt;
&lt;li&gt;打包体积优化手段&lt;/li&gt;
&lt;li&gt;第三方组件库按需引入配置&lt;/li&gt;
&lt;li&gt;unplugin-auto-import 自动导入hooks&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十三网络请求封装&#34;&gt;十三、网络请求封装&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;axios 请求拦截、响应拦截封装&lt;/li&gt;
&lt;li&gt;全局 loading、统一错误处理&lt;/li&gt;
&lt;li&gt;token 过期无感刷新实现逻辑&lt;/li&gt;
&lt;li&gt;重复请求取消方案 CancelToken&lt;/li&gt;
&lt;li&gt;请求并发处理&lt;/li&gt;
&lt;li&gt;封装自定义请求Hook&lt;/li&gt;
&lt;li&gt;SWR / React Query 数据请求缓存库原理&lt;/li&gt;
&lt;li&gt;React Query 自动重请求、缓存失效策略&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十四性能优化专题&#34;&gt;十四、性能优化专题&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;组件无效重渲染全部诱因&lt;/li&gt;
&lt;li&gt;memo 缓存函数组件条件&lt;/li&gt;
&lt;li&gt;useCallback 缓存函数使用场景&lt;/li&gt;
&lt;li&gt;useMemo 缓存计算结果适用场景&lt;/li&gt;
&lt;li&gt;列表渲染优化策略&lt;/li&gt;
&lt;li&gt;虚拟列表 react-window / react-virtualized 原理&lt;/li&gt;
&lt;li&gt;图片懒加载实现&lt;/li&gt;
&lt;li&gt;路由懒加载分包优化首屏&lt;/li&gt;
&lt;li&gt;大组件拆分、状态下沉优化&lt;/li&gt;
&lt;li&gt;避免在render内创建函数/对象&lt;/li&gt;
&lt;li&gt;React DevTools Profiler 排查卡顿&lt;/li&gt;
&lt;li&gt;减少Context频繁更新范围&lt;/li&gt;
&lt;li&gt;定时器、订阅事件组件卸载清理&lt;/li&gt;
&lt;li&gt;打包体积压缩：gzip、剔除无用依赖&lt;/li&gt;
&lt;li&gt;并发更新优化用户交互体验&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十五进阶底层原理&#34;&gt;十五、进阶底层原理&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Fiber 架构解决旧架构什么问题&lt;/li&gt;
&lt;li&gt;Fiber 节点结构、任务拆分机制&lt;/li&gt;
&lt;li&gt;协调阶段、提交阶段分工&lt;/li&gt;
&lt;li&gt;可中断、可恢复、可优先级调度原理&lt;/li&gt;
&lt;li&gt;调和过程完整流程&lt;/li&gt;
&lt;li&gt;批量更新实现机制&lt;/li&gt;
&lt;li&gt;合成事件系统底层池化机制&lt;/li&gt;
&lt;li&gt;React 事务机制&lt;/li&gt;
&lt;li&gt;Portal 传送门实现原理，事件冒泡特点&lt;/li&gt;
&lt;li&gt;ErrorBoundary 错误捕获范围，无法捕获哪些错误&lt;/li&gt;
&lt;li&gt;React 服务端渲染 SSR 流程&lt;/li&gt;
&lt;li&gt;Next.js 与 CRA 区别，SSR/SSG/ISR 概念&lt;/li&gt;
&lt;li&gt;Hydrate 水合作用，水合不匹配成因&lt;/li&gt;
&lt;li&gt;RSC React Server Components 运行机制&lt;/li&gt;
&lt;li&gt;微前端中 React 应用隔离方案&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十六项目实战场景题&#34;&gt;十六、项目实战场景题&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;项目目录分层架构设计&lt;/li&gt;
&lt;li&gt;状态管理选型理由&lt;/li&gt;
&lt;li&gt;大型表单封装思路&lt;/li&gt;
&lt;li&gt;页面按钮、接口权限控制实现&lt;/li&gt;
&lt;li&gt;首屏加载缓慢优化方案&lt;/li&gt;
&lt;li&gt;列表大量数据渲染卡顿解决&lt;/li&gt;
&lt;li&gt;全局弹窗、消息提示封装&lt;/li&gt;
&lt;li&gt;路由鉴权、未登录跳转逻辑&lt;/li&gt;
&lt;li&gt;组件复用抽离自定义Hook规范&lt;/li&gt;
&lt;li&gt;线上报错捕获监控方案&lt;/li&gt;
&lt;li&gt;多环境变量、多渠道打包配置&lt;/li&gt;
&lt;li&gt;防抖节流在搜索框场景实现&lt;/li&gt;
&lt;li&gt;页面返回保留表单状态实现&lt;/li&gt;
&lt;li&gt;重复提交接口拦截处理&lt;/li&gt;
&lt;li&gt;React 项目迁移 TS 改造思路&lt;/li&gt;
&lt;/ol&gt;</description>
    </item>
    <item>
      <title>Redis 相关面试题整理</title>
      <link>https://lv-blog.pages.dev/posts/programming/for-interview/redis-interview-questions/</link>
      <pubDate>Wed, 15 Jul 2026 00:46:10 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/for-interview/redis-interview-questions/</guid>
      <description>&lt;h2 id=&#34;你的项目的哪些场景使用了-redis&#34;&gt;你的项目的哪些场景使用了 redis&lt;/h2&gt;
&lt;h2 id=&#34;如果发生了缓存击穿穿透雪崩如何解决&#34;&gt;如果发生了缓存击穿、穿透、雪崩如何解决&lt;/h2&gt;
&lt;h2 id=&#34;redis-作为缓存-mysql的数据如何与redis进行同步&#34;&gt;redis 作为缓存， mysql的数据如何与redis进行同步？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;先介绍业务，看看业务符合什么场景&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一致性较高场景&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;双写一致
&lt;ul&gt;
&lt;li&gt;读&lt;/li&gt;
&lt;li&gt;写 | 延迟双删&lt;/li&gt;
&lt;li&gt;分布式锁
&lt;ul&gt;
&lt;li&gt;读多写少
&lt;ul&gt;
&lt;li&gt;共享锁&lt;/li&gt;
&lt;li&gt;排它锁&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;允许延迟一致&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;介绍一下你的异步方案&#34;&gt;介绍一下你的异步方案&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;允许延时一致的业务，采用异步通知
&lt;ul&gt;
&lt;li&gt;MQ消息中间件&lt;/li&gt;
&lt;li&gt;Canal中间件&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;强一致性（Redisson读写锁）
&lt;ul&gt;
&lt;li&gt;共享锁
&lt;ul&gt;
&lt;li&gt;阻塞写操作&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;排它锁
&lt;ul&gt;
&lt;li&gt;阻塞读和写操作&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;redis作为缓存数据的持久化是怎么做的&#34;&gt;Redis作为缓存，数据的持久化是怎么做的？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;RDB
&lt;ul&gt;
&lt;li&gt;save&lt;/li&gt;
&lt;li&gt;bgsave&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;AOF&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;rdb-的执行原理&#34;&gt;RDB 的执行原理？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;fork主进程得到子进程&lt;/li&gt;
&lt;li&gt;子进程共享主进程的内存数据（复制页表）&lt;/li&gt;
&lt;li&gt;copy-on-write&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;aof-的执行原理&#34;&gt;AOF 的执行原理&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;配置项&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;always&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;everysec&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;no&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;重写触发&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;bgrewriteaof&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;rdb-和-aof-对比&#34;&gt;RDB 和 AOF 对比&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;持久化方式&lt;/li&gt;
&lt;li&gt;数据完整性&lt;/li&gt;
&lt;li&gt;文件大小&lt;/li&gt;
&lt;li&gt;宕机恢复速度&lt;/li&gt;
&lt;li&gt;数据恢复优先级&lt;/li&gt;
&lt;li&gt;系统资源占用&lt;/li&gt;
&lt;li&gt;使用场景&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;redis-的key过期了会立即删除吗&#34;&gt;redis 的key过期了会立即删除吗&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;惰性删除&lt;/li&gt;
&lt;li&gt;定期删除
&lt;ul&gt;
&lt;li&gt;SLOW（10hz）&lt;/li&gt;
&lt;li&gt;FAST&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Redis的过期策略：惰性删除+定期删除 配合使用&lt;/p&gt;
&lt;h2 id=&#34;redis-数据淘汰策略&#34;&gt;Redis 数据淘汰策略&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;noeviction&lt;/li&gt;
&lt;li&gt;volatile-ttl&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;allkeys-random&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;volatile-random&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;allkeys-lru&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;volatile-lru&lt;/li&gt;
&lt;li&gt;allkeys-lfu&lt;/li&gt;
&lt;li&gt;volatile-lfu&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;数据库有1000万数据redis只能缓存20万如何保证redis中的数据都是热点数据&#34;&gt;数据库有1000万数据，redis只能缓存20万，如何保证redis中的数据都是热点数据？&lt;/h2&gt;
&lt;p&gt;使用 allkeys-lru&lt;/p&gt;</description>
    </item>
    <item>
      <title>Vue 相关面试题整理</title>
      <link>https://lv-blog.pages.dev/posts/programming/frontend/vue-interview-questions/</link>
      <pubDate>Wed, 15 Jul 2026 00:46:10 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/frontend/vue-interview-questions/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;从互联网整理而来&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;一jsts-前置基础&#34;&gt;一、JS/TS 前置基础&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;var、let、const 区别&lt;/li&gt;
&lt;li&gt;原型、原型链原理&lt;/li&gt;
&lt;li&gt;闭包概念、使用场景、内存泄漏风险&lt;/li&gt;
&lt;li&gt;同步异步、宏任务微任务执行顺序&lt;/li&gt;
&lt;li&gt;Promise 三种状态、链式调用、静态方法&lt;/li&gt;
&lt;li&gt;async/await 底层原理&lt;/li&gt;
&lt;li&gt;数组常用遍历方法差异&lt;/li&gt;
&lt;li&gt;深浅拷贝实现与区别&lt;/li&gt;
&lt;li&gt;Object.defineProperty 与 Proxy 对比&lt;/li&gt;
&lt;li&gt;Reflect 对象作用&lt;/li&gt;
&lt;li&gt;箭头函数与普通函数区别&lt;/li&gt;
&lt;li&gt;解构赋值、展开运算符&lt;/li&gt;
&lt;li&gt;ES6 模块 import/export 与 CommonJS 区别&lt;/li&gt;
&lt;li&gt;TypeScript 泛型、接口、类型推导&lt;/li&gt;
&lt;li&gt;EventLoop 完整执行流程&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;二vue2-基础核心&#34;&gt;二、Vue2 基础核心&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Vue 双向绑定底层原理&lt;/li&gt;
&lt;li&gt;Object.defineProperty 如何监听对象、数组变化&lt;/li&gt;
&lt;li&gt;Vue2 数组重写了哪些方法，为什么不能监听下标修改&lt;/li&gt;
&lt;li&gt;Dep、Watcher、Observer 三者关系&lt;/li&gt;
&lt;li&gt;什么是响应式依赖收集、派发更新&lt;/li&gt;
&lt;li&gt;数据劫持流程完整过程&lt;/li&gt;
&lt;li&gt;computed 和 watch 区别&lt;/li&gt;
&lt;li&gt;computed 缓存实现原理&lt;/li&gt;
&lt;li&gt;methods、computed、watch 使用场景区分&lt;/li&gt;
&lt;li&gt;Vue 生命周期全部钩子及执行时机&lt;/li&gt;
&lt;li&gt;created、mounted、updated、destroyed 使用场景&lt;/li&gt;
&lt;li&gt;父子组件生命周期执行顺序&lt;/li&gt;
&lt;li&gt;v-if 和 v-show 底层区别与性能差异&lt;/li&gt;
&lt;li&gt;v-for 绑定 key 的作用，key 不能用 index 的原因&lt;/li&gt;
&lt;li&gt;v-if 和 v-for 同时使用的优先级与问题&lt;/li&gt;
&lt;li&gt;v-model 底层语法糖实现&lt;/li&gt;
&lt;li&gt;修饰符 .lazy .number .trim 原理&lt;/li&gt;
&lt;li&gt;指令自定义实现，钩子函数有哪些&lt;/li&gt;
&lt;li&gt;过滤器 filter 使用场景，Vue3 废弃原因&lt;/li&gt;
&lt;li&gt;插值表达式、v-text、v-html 区别&lt;/li&gt;
&lt;li&gt;Vue 模板编译流程&lt;/li&gt;
&lt;li&gt;render 函数与 template 关系&lt;/li&gt;
&lt;li&gt;VNode 虚拟 DOM 结构作用&lt;/li&gt;
&lt;li&gt;Diff 算法执行流程&lt;/li&gt;
&lt;li&gt;Vue2 Diff 同层比较、key 作用、头尾指针优化&lt;/li&gt;
&lt;li&gt;patch 函数更新逻辑&lt;/li&gt;
&lt;li&gt;nextTick 原理，微任务/宏任务降级策略&lt;/li&gt;
&lt;li&gt;$nextTick 使用场景&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;三vue2-组件通信&#34;&gt;三、Vue2 组件通信&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;父子组件 props 传递规则，单向数据流&lt;/li&gt;
&lt;li&gt;props 类型校验、默认值、必填配置&lt;/li&gt;
&lt;li&gt;$emit 子传父实现&lt;/li&gt;
&lt;li&gt;.sync 修饰符作用，Vue3 移除原因&lt;/li&gt;
&lt;li&gt;$parent、$children、$refs 获取组件/元素&lt;/li&gt;
&lt;li&gt;provide / inject 使用场景与响应式缺陷&lt;/li&gt;
&lt;li&gt;EventBus 事件总线实现、内存泄漏问题&lt;/li&gt;
&lt;li&gt;Vuex 全局状态通信完整流程&lt;/li&gt;
&lt;li&gt;$attrs、$listeners 跨层级透传&lt;/li&gt;
&lt;li&gt;跨页面、多层级组件通信方案对比&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;四vuex-状态管理&#34;&gt;四、Vuex 状态管理&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Vuex 五大核心概念 state、getters、mutations、actions、modules&lt;/li&gt;
&lt;li&gt;mutations 必须同步、actions 异步原因&lt;/li&gt;
&lt;li&gt;commit 和 dispatch 区别&lt;/li&gt;
&lt;li&gt;getters 缓存特性&lt;/li&gt;
&lt;li&gt;modules 模块划分，命名空间 namespaced&lt;/li&gt;
&lt;li&gt;辅助函数 mapState/mapGetters/mapMutations/mapActions 使用&lt;/li&gt;
&lt;li&gt;Vuex 持久化存储方案&lt;/li&gt;
&lt;li&gt;Vuex 严格模式 strict 作用&lt;/li&gt;
&lt;li&gt;多个组件同时修改同一 state 数据流&lt;/li&gt;
&lt;li&gt;Vuex 底层响应式原理&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;五vue-router-23&#34;&gt;五、Vue Router 2/3&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;SPA 单页面路由实现原理&lt;/li&gt;
&lt;li&gt;hash 模式与 history 模式底层区别&lt;/li&gt;
&lt;li&gt;history 模式后端 nginx 配置问题&lt;/li&gt;
&lt;li&gt;路由导航守卫分类：全局、路由独享、组件内&lt;/li&gt;
&lt;li&gt;导航守卫执行完整顺序&lt;/li&gt;
&lt;li&gt;$route 和 $router 区别&lt;/li&gt;
&lt;li&gt;路由传参 params 和 query 差异&lt;/li&gt;
&lt;li&gt;params 刷新丢失参数解决方案&lt;/li&gt;
&lt;li&gt;动态路由匹配、路由嵌套&lt;/li&gt;
&lt;li&gt;路由懒加载实现与分包&lt;/li&gt;
&lt;li&gt;addRoutes、addRoute 动态添加路由&lt;/li&gt;
&lt;li&gt;路由元信息 meta 使用场景&lt;/li&gt;
&lt;li&gt;路由缓存 keep-alive 原理&lt;/li&gt;
&lt;li&gt;include/exclude/max 参数作用&lt;/li&gt;
&lt;li&gt;activated、deactivated 生命周期钩子&lt;/li&gt;
&lt;li&gt;路由跳转 push、replace、go 区别&lt;/li&gt;
&lt;li&gt;登录鉴权全局路由拦截实现&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;六vue2-进阶知识点&#34;&gt;六、Vue2 进阶知识点&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;keep-alive 缓存组件底层逻辑&lt;/li&gt;
&lt;li&gt;异步组件、组件懒加载&lt;/li&gt;
&lt;li&gt;组件递归实现菜单、树形结构&lt;/li&gt;
&lt;li&gt;$once、$off、$on 事件方法&lt;/li&gt;
&lt;li&gt;插槽分类：默认插槽、具名插槽、作用域插槽&lt;/li&gt;
&lt;li&gt;作用域插槽数据传递原理&lt;/li&gt;
&lt;li&gt;v-once 指令作用&lt;/li&gt;
&lt;li&gt;Vue 模板编译生成 AST 抽象语法树&lt;/li&gt;
&lt;li&gt;异步更新队列机制&lt;/li&gt;
&lt;li&gt;页面大量数据渲染卡顿优化方案&lt;/li&gt;
&lt;li&gt;Object.freeze 冻结数据对响应式的影响&lt;/li&gt;
&lt;li&gt;$set 原理，什么场景必须使用&lt;/li&gt;
&lt;li&gt;Vue2 响应式存在的缺陷&lt;/li&gt;
&lt;li&gt;全局过滤器、全局指令、全局组件注册&lt;/li&gt;
&lt;li&gt;mixin 混入原理、合并规则、冲突问题&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;七vue3-核心升级composition-api&#34;&gt;七、Vue3 核心升级（Composition API）&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Vue3 相比 Vue2 性能提升点&lt;/li&gt;
&lt;li&gt;Vue3 响应式改用 Proxy 优势&lt;/li&gt;
&lt;li&gt;Proxy 对比 Object.defineProperty 解决了哪些痛点&lt;/li&gt;
&lt;li&gt;Reflect 配合 Proxy 的作用&lt;/li&gt;
&lt;li&gt;reactive、ref 区别与底层实现&lt;/li&gt;
&lt;li&gt;ref 为什么基础类型需要包裹对象&lt;/li&gt;
&lt;li&gt;toRef、toRefs 使用场景，解决的问题&lt;/li&gt;
&lt;li&gt;computed 在 setup 中使用方式&lt;/li&gt;
&lt;li&gt;watch、watchEffect 区别&lt;/li&gt;
&lt;li&gt;watch 监听对象、数组深度监听配置&lt;/li&gt;
&lt;li&gt;setup 执行时机，this 指向问题&lt;/li&gt;
&lt;li&gt;setup 参数 props、context 内容&lt;/li&gt;
&lt;li&gt;Composition API 对比 Options API 优势&lt;/li&gt;
&lt;li&gt;script setup 语法糖带来的变化&lt;/li&gt;
&lt;li&gt;script setup 中 defineProps、defineEmits、defineExpose&lt;/li&gt;
&lt;li&gt;生命周期钩子组合式写法 onMounted/onUpdated 等&lt;/li&gt;
&lt;li&gt;getCurrentInstance 获取组件实例&lt;/li&gt;
&lt;li&gt;provide / inject 在 Vue3 中如何实现响应式&lt;/li&gt;
&lt;li&gt;自定义 hooks 封装思路，复用逻辑&lt;/li&gt;
&lt;li&gt;Vue3 生命周期完整列表，与 Vue2 对应关系&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;八vue3-模板编译diff-优化&#34;&gt;八、Vue3 模板、编译、Diff 优化&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Vue3 模板编译优化：PatchFlags 标记&lt;/li&gt;
&lt;li&gt;静态提升原理，减少 VNode 创建开销&lt;/li&gt;
&lt;li&gt;缓存内联事件处理函数&lt;/li&gt;
&lt;li&gt;Vue3 Diff 算法优化：最长递增子序列&lt;/li&gt;
&lt;li&gt;Diff 对比流程相比 Vue2 改进点&lt;/li&gt;
&lt;li&gt;Fragment 根节点多标签支持原理&lt;/li&gt;
&lt;li&gt;Teleport 传送门组件底层实现&lt;/li&gt;
&lt;li&gt;Suspense 异步组件加载处理&lt;/li&gt;
&lt;li&gt;v-model 在 Vue3 语法变更，多 v-model 实现&lt;/li&gt;
&lt;li&gt;.v-model 修饰符自定义处理&lt;/li&gt;
&lt;li&gt;插槽 v-slot 简写语法变化&lt;/li&gt;
&lt;li&gt;Vue3 移除 filter 过滤器替代方案&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;九piniavue3-状态管理&#34;&gt;九、Pinia（Vue3 状态管理）&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Pinia 相比 Vuex 的优势&lt;/li&gt;
&lt;li&gt;Pinia 核心概念 state、getters、actions&lt;/li&gt;
&lt;li&gt;Pinia 支持同步异步，不再区分 mutations&lt;/li&gt;
&lt;li&gt;defineStore 定义仓库，id 作用&lt;/li&gt;
&lt;li&gt;直接修改 state 与 $patch 批量更新区别&lt;/li&gt;
&lt;li&gt;$reset、$subscribe、$onAction 使用场景&lt;/li&gt;
&lt;li&gt;Pinia 模块化拆分，无需命名空间&lt;/li&gt;
&lt;li&gt;Pinia 持久化插件使用&lt;/li&gt;
&lt;li&gt;setup 语法下使用 Pinia&lt;/li&gt;
&lt;li&gt;多个仓库互相调用数据方法&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十vue-router-4vue3&#34;&gt;十、Vue Router 4（Vue3）&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;createRouter、createWebHashHistory、createWebHistory&lt;/li&gt;
&lt;li&gt;RouterView、RouterLink v-slot 插槽用法&lt;/li&gt;
&lt;li&gt;useRoute、useRouter 组合式 API 获取路由实例&lt;/li&gt;
&lt;li&gt;动态路由 addRoute 替换 addRoutes&lt;/li&gt;
&lt;li&gt;路由守卫组合式写法&lt;/li&gt;
&lt;li&gt;路由缓存与 Suspense 配合&lt;/li&gt;
&lt;li&gt;路由元类型 TS 类型提示处理&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十一vue3-高级特性&#34;&gt;十一、Vue3 高级特性&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;watchPostEffect、watchSyncEffect 区别&lt;/li&gt;
&lt;li&gt;shallowRef、shallowReactive 浅层响应式作用&lt;/li&gt;
&lt;li&gt;readonly、shallowReadonly 只读代理&lt;/li&gt;
&lt;li&gt;customRef 自定义响应式引用&lt;/li&gt;
&lt;li&gt;effectScope 作用域收集副作用&lt;/li&gt;
&lt;li&gt;defineCustomElement 构建原生 webComponent&lt;/li&gt;
&lt;li&gt;Vue3 全局 API 变更 createApp 替代 new Vue()&lt;/li&gt;
&lt;li&gt;app.config 全局配置项&lt;/li&gt;
&lt;li&gt;全局组件、指令、插件注册方式变化&lt;/li&gt;
&lt;li&gt;Transition、TransitionGroup 动画组件原理&lt;/li&gt;
&lt;li&gt;v-memo 缓存 VNode 优化渲染&lt;/li&gt;
&lt;li&gt;异步 setup 函数配合 Suspense&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十二工程化--构建工具&#34;&gt;十二、工程化 &amp;amp; 构建工具&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Vue CLI 与 Vite 底层构建区别&lt;/li&gt;
&lt;li&gt;Vite 冷启动快的原理，esbuild 预构建&lt;/li&gt;
&lt;li&gt;Vite 热更新 HMR 实现机制&lt;/li&gt;
&lt;li&gt;vite.config.js 常用配置&lt;/li&gt;
&lt;li&gt;webpack 打包 Vue 文件流程 vue-loader&lt;/li&gt;
&lt;li&gt;.vue SFC 单文件组件解析过程&lt;/li&gt;
&lt;li&gt;scoped 样式隔离原理，深度选择器 /deep/ ::v-deep :deep()&lt;/li&gt;
&lt;li&gt;CSS Module 使用方式&lt;/li&gt;
&lt;li&gt;环境变量 .env 文件区分开发测试生产&lt;/li&gt;
&lt;li&gt;跨域代理 proxy 配置&lt;/li&gt;
&lt;li&gt;打包体积优化方案&lt;/li&gt;
&lt;li&gt;分包、懒加载、gzip 压缩配置&lt;/li&gt;
&lt;li&gt;TS 在 Vue 项目中配置声明文件&lt;/li&gt;
&lt;li&gt;第三方 UI 库按需引入配置&lt;/li&gt;
&lt;li&gt;全局自动导入组件、API 插件 unplugin-auto-import&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十三网络请求与封装&#34;&gt;十三、网络请求与封装&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;axios 拦截器请求、响应封装思路&lt;/li&gt;
&lt;li&gt;请求 loading、统一错误处理封装&lt;/li&gt;
&lt;li&gt;token 过期自动刷新逻辑&lt;/li&gt;
&lt;li&gt;请求取消、重复请求拦截方案&lt;/li&gt;
&lt;li&gt;并发请求处理&lt;/li&gt;
&lt;li&gt;接口数据统一格式化处理&lt;/li&gt;
&lt;li&gt;封装请求 hooks 适配 Vue3&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十四性能优化专项&#34;&gt;十四、性能优化专项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;减少不必要组件渲染手段&lt;/li&gt;
&lt;li&gt;v-once、v-memo 使用场景&lt;/li&gt;
&lt;li&gt;长列表虚拟滚动实现原理&lt;/li&gt;
&lt;li&gt;响应式数据避免不必要监听&lt;/li&gt;
&lt;li&gt;computed 缓存减少重复计算&lt;/li&gt;
&lt;li&gt;图片懒加载方案&lt;/li&gt;
&lt;li&gt;路由懒加载分包优化&lt;/li&gt;
&lt;li&gt;keep-alive 合理缓存减少重复请求&lt;/li&gt;
&lt;li&gt;避免频繁触发 watch&lt;/li&gt;
&lt;li&gt;大列表数据冻结 Object.freeze&lt;/li&gt;
&lt;li&gt;减少 DOM 操作，合理使用虚拟 DOM&lt;/li&gt;
&lt;li&gt;打包体积优化：Tree-Shaking、剔除无用依赖&lt;/li&gt;
&lt;li&gt;Vite/Webpack 构建速度优化&lt;/li&gt;
&lt;li&gt;内存泄漏常见场景：定时器、事件监听、未销毁订阅&lt;/li&gt;
&lt;li&gt;Chrome Performance 面板排查页面卡顿&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十五混合插件拓展开发&#34;&gt;十五、混合、插件、拓展开发&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Vue2 mixin 缺陷，Vue3 用 hooks 替代原因&lt;/li&gt;
&lt;li&gt;Vue 插件开发完整结构 install 方法&lt;/li&gt;
&lt;li&gt;全局自定义指令完整开发&lt;/li&gt;
&lt;li&gt;封装业务通用组件规范&lt;/li&gt;
&lt;li&gt;二次封装 Element Plus / Ant Design Vue&lt;/li&gt;
&lt;li&gt;封装全局弹窗、消息提示组件&lt;/li&gt;
&lt;li&gt;自定义全局权限指令 v-permission&lt;/li&gt;
&lt;li&gt;页面权限、按钮权限实现方案&lt;/li&gt;
&lt;li&gt;全局错误捕获 errorHandler&lt;/li&gt;
&lt;li&gt;埋点、全局请求监控插件封装&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十六项目实战场景问答题&#34;&gt;十六、项目实战场景问答题&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;项目整体架构分层设计&lt;/li&gt;
&lt;li&gt;Vue2 升级 Vue3 迁移改造遇到的问题&lt;/li&gt;
&lt;li&gt;大型项目状态管理选型 Vuex / Pinia 理由&lt;/li&gt;
&lt;li&gt;复杂树形菜单、表格组件封装思路&lt;/li&gt;
&lt;li&gt;表单校验全局统一封装方案&lt;/li&gt;
&lt;li&gt;页面权限控制完整实现流程&lt;/li&gt;
&lt;li&gt;多环境配置、多渠道打包处理&lt;/li&gt;
&lt;li&gt;首屏加载速度优化做了哪些处理&lt;/li&gt;
&lt;li&gt;路由鉴权、未登录拦截逻辑&lt;/li&gt;
&lt;li&gt;列表大量数据渲染卡顿如何解决&lt;/li&gt;
&lt;li&gt;项目打包体积过大优化方案&lt;/li&gt;
&lt;li&gt;页面缓存、返回保留表单状态实现&lt;/li&gt;
&lt;li&gt;接口并发冲突、重复提交拦截&lt;/li&gt;
&lt;li&gt;移动端适配方案 vw/vh、rem&lt;/li&gt;
&lt;li&gt;线上报错监控、异常捕获方案&lt;/li&gt;
&lt;/ol&gt;</description>
    </item>
    <item>
      <title>微信小程序 相关面试题整理</title>
      <link>https://lv-blog.pages.dev/posts/programming/frontend/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%9B%B8%E5%85%B3%E9%9D%A2%E8%AF%95%E9%A2%98/</link>
      <pubDate>Wed, 15 Jul 2026 00:46:10 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/frontend/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%9B%B8%E5%85%B3%E9%9D%A2%E8%AF%95%E9%A2%98/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;从互联网整理而来&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;一基础概念与运行机制&#34;&gt;一、基础概念与运行机制&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;小程序与H5、App的核心区别&lt;/li&gt;
&lt;li&gt;小程序双线程模型分别是什么，各自职责&lt;/li&gt;
&lt;li&gt;逻辑层与视图层通信方式&lt;/li&gt;
&lt;li&gt;小程序渲染流程完整过程&lt;/li&gt;
&lt;li&gt;小程序启动流程（冷启动、热启动）&lt;/li&gt;
&lt;li&gt;冷启动和热启动的差异&lt;/li&gt;
&lt;li&gt;小程序分包加载机制概念&lt;/li&gt;
&lt;li&gt;主包与分包限制规则&lt;/li&gt;
&lt;li&gt;独立分包和普通分包区别&lt;/li&gt;
&lt;li&gt;小程序的生命周期分类（应用、页面、组件）&lt;/li&gt;
&lt;li&gt;小程序页面栈规则，最多存放多少页面&lt;/li&gt;
&lt;li&gt;小程序登录流程整体逻辑&lt;/li&gt;
&lt;li&gt;微信授权两种类型区别（基础授权、隐私授权）&lt;/li&gt;
&lt;li&gt;小程序原生宿主环境提供哪些能力&lt;/li&gt;
&lt;li&gt;小程序更新机制，静默更新与主动更新&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;二文件结构与配置&#34;&gt;二、文件结构与配置&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;小程序四种核心文件作用（json/wxml/wxss/js）&lt;/li&gt;
&lt;li&gt;app.json 全局配置常用字段&lt;/li&gt;
&lt;li&gt;page.json 页面配置优先级与app.json关系&lt;/li&gt;
&lt;li&gt;sitemap.json 作用&lt;/li&gt;
&lt;li&gt;project.config.json 用途&lt;/li&gt;
&lt;li&gt;app.js 全局App实例生命周期&lt;/li&gt;
&lt;li&gt;页面js Page构造器生命周期&lt;/li&gt;
&lt;li&gt;组件js Component构造器生命周期&lt;/li&gt;
&lt;li&gt;usingComponents 引入组件配置&lt;/li&gt;
&lt;li&gt;全局样式app.wxss和页面wxss权重规则&lt;/li&gt;
&lt;li&gt;wxss与css差异，特有特性&lt;/li&gt;
&lt;li&gt;rpx单位换算规则，适配原理&lt;/li&gt;
&lt;li&gt;小程序支持的选择器有哪些，不支持哪些&lt;/li&gt;
&lt;li&gt;图片、静态资源本地与线上引入规则&lt;/li&gt;
&lt;li&gt;分包配置subpackages字段参数含义&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;三wxml-模板语法&#34;&gt;三、WXML 模板语法&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;WXML数据绑定语法规则&lt;/li&gt;
&lt;li&gt;插值表达式支持哪些运算&lt;/li&gt;
&lt;li&gt;wx:if、wx:elif、wx:else 条件渲染&lt;/li&gt;
&lt;li&gt;hidden属性与wx:if性能差异&lt;/li&gt;
&lt;li&gt;wx:for列表渲染，wx:key作用&lt;/li&gt;
&lt;li&gt;wx:key使用规范，禁止index的场景&lt;/li&gt;
&lt;li&gt;block标签作用，是否生成真实节点&lt;/li&gt;
&lt;li&gt;模板template定义与引入，数据传递&lt;/li&gt;
&lt;li&gt;wxs脚本作用，运行环境限制&lt;/li&gt;
&lt;li&gt;wxs与js的区别，能否调用小程序API&lt;/li&gt;
&lt;li&gt;事件绑定bind、catch、capture-bind区别&lt;/li&gt;
&lt;li&gt;mut-bind互斥事件作用&lt;/li&gt;
&lt;li&gt;事件传参几种实现方式&lt;/li&gt;
&lt;li&gt;数据双向绑定model语法&lt;/li&gt;
&lt;li&gt;标签属性布尔值绑定规则&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;四组件系统原生自定义组件&#34;&gt;四、组件系统（原生+自定义组件）&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;小程序自定义组件创建完整结构&lt;/li&gt;
&lt;li&gt;Component中properties传参配置规则&lt;/li&gt;
&lt;li&gt;properties三种数据监听方式&lt;/li&gt;
&lt;li&gt;data、properties、observers执行顺序&lt;/li&gt;
&lt;li&gt;observers监听对象、数组深层变化写法&lt;/li&gt;
&lt;li&gt;组件生命周期完整钩子&lt;/li&gt;
&lt;li&gt;lifetimes与pageLifetimes区别&lt;/li&gt;
&lt;li&gt;组件插槽slot，具名插槽使用&lt;/li&gt;
&lt;li&gt;组件父子通信方式&lt;/li&gt;
&lt;li&gt;triggerEvent触发自定义事件传参&lt;/li&gt;
&lt;li&gt;selectComponent、selectAllComponents获取子组件&lt;/li&gt;
&lt;li&gt;behaviors复用逻辑，合并规则&lt;/li&gt;
&lt;li&gt;原生内置常用容器、表单、媒体组件&lt;/li&gt;
&lt;li&gt;scroll-view滚动注意事项&lt;/li&gt;
&lt;li&gt;movable-area、movable-view实现拖拽原理&lt;/li&gt;
&lt;li&gt;canvas新旧版本差异，2d画布使用&lt;/li&gt;
&lt;li&gt;web-view嵌入H5通信方案&lt;/li&gt;
&lt;li&gt;cover-view、cover-image使用限制场景&lt;/li&gt;
&lt;li&gt;自定义组件样式隔离options配置&lt;/li&gt;
&lt;li&gt;组件pureDataPattern作用&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;五数据管理与渲染更新&#34;&gt;五、数据管理与渲染更新&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;setData底层更新原理&lt;/li&gt;
&lt;li&gt;setData频繁调用性能问题&lt;/li&gt;
&lt;li&gt;setData单次数据大小限制&lt;/li&gt;
&lt;li&gt;局部更新数据简写写法&lt;/li&gt;
&lt;li&gt;直接修改this.data不调用setData为什么不更新视图&lt;/li&gt;
&lt;li&gt;复杂对象、数组更新setData写法&lt;/li&gt;
&lt;li&gt;全局数据共享几种方案&lt;/li&gt;
&lt;li&gt;getApp()全局变量优缺点&lt;/li&gt;
&lt;li&gt;globalData跨页面同步更新缺陷&lt;/li&gt;
&lt;li&gt;数据本地持久化storage存储限制&lt;/li&gt;
&lt;li&gt;wx.setStorage同步异步API区别&lt;/li&gt;
&lt;li&gt;storage大数据存储优化方案&lt;/li&gt;
&lt;li&gt;页面间数据传递方式对比&lt;/li&gt;
&lt;li&gt;页面栈取上一页实例方法&lt;/li&gt;
&lt;li&gt;大数据列表渲染卡顿优化思路&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;六路由与页面跳转&#34;&gt;六、路由与页面跳转&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;五种路由API区别（navigateTo/redirectTo/reLaunch/switchTab/navigateBack）&lt;/li&gt;
&lt;li&gt;switchTab跳转限制条件&lt;/li&gt;
&lt;li&gt;navigateTo无法跳tab页面解决方案&lt;/li&gt;
&lt;li&gt;路由传参两种方式，长参数丢失问题&lt;/li&gt;
&lt;li&gt;页面返回监听onUnload、onShow触发时机&lt;/li&gt;
&lt;li&gt;获取当前页面栈方法getCurrentPages()&lt;/li&gt;
&lt;li&gt;路由拦截统一封装思路&lt;/li&gt;
&lt;li&gt;tabBar配置规则，自定义tabBar实现&lt;/li&gt;
&lt;li&gt;自定义tabBar踩坑点&lt;/li&gt;
&lt;li&gt;页面跳转后保留表单状态方案&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;七网络请求与后端交互&#34;&gt;七、网络请求与后端交互&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;wx.request请求基础配置&lt;/li&gt;
&lt;li&gt;request合法域名校验规则，开发环境规避&lt;/li&gt;
&lt;li&gt;小程序请求携带cookie机制&lt;/li&gt;
&lt;li&gt;请求header统一封装token思路&lt;/li&gt;
&lt;li&gt;拦截器封装wx.request方案&lt;/li&gt;
&lt;li&gt;并发请求、请求超时处理&lt;/li&gt;
&lt;li&gt;文件上传wx.uploadFile参数配置&lt;/li&gt;
&lt;li&gt;文件下载wx.downloadFile使用场景&lt;/li&gt;
&lt;li&gt;websocket实时通信完整流程&lt;/li&gt;
&lt;li&gt;socket断线重连实现逻辑&lt;/li&gt;
&lt;li&gt;接口返回加密数据解密处理&lt;/li&gt;
&lt;li&gt;批量请求统一捕获异常&lt;/li&gt;
&lt;li&gt;小程序不支持跨域的根本原因&lt;/li&gt;
&lt;li&gt;上传图片压缩、裁剪处理&lt;/li&gt;
&lt;li&gt;上传进度监听API&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;八登录授权用户信息&#34;&gt;八、登录、授权、用户信息&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;wx.login获取code作用&lt;/li&gt;
&lt;li&gt;code换取openid完整流程&lt;/li&gt;
&lt;li&gt;openid、unionid区别与生成规则&lt;/li&gt;
&lt;li&gt;隐私保护新规下获取用户头像昵称方案&lt;/li&gt;
&lt;li&gt;getUserInfo接口废弃替代方案&lt;/li&gt;
&lt;li&gt;手机号一键登录流程&lt;/li&gt;
&lt;li&gt;授权scope各权限含义&lt;/li&gt;
&lt;li&gt;用户拒绝授权后重新引导授权逻辑&lt;/li&gt;
&lt;li&gt;登录态session_key过期处理&lt;/li&gt;
&lt;li&gt;第三方登录、关联账号实现&lt;/li&gt;
&lt;li&gt;登录状态持久化存储方案&lt;/li&gt;
&lt;li&gt;多端打通unionid获取条件&lt;/li&gt;
&lt;li&gt;隐私协议弹窗实现规范&lt;/li&gt;
&lt;li&gt;小程序订阅消息下发流程&lt;/li&gt;
&lt;li&gt;模板消息与订阅消息区别&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;九媒体图片地图设备api&#34;&gt;九、媒体、图片、地图、设备API&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;wx.chooseMedia选择图片视频参数&lt;/li&gt;
&lt;li&gt;图片预览wx.previewImage使用&lt;/li&gt;
&lt;li&gt;图片本地缓存方案&lt;/li&gt;
&lt;li&gt;录音、播放音频API使用&lt;/li&gt;
&lt;li&gt;video视频播放常见问题&lt;/li&gt;
&lt;li&gt;map地图组件标记、覆盖物绘制&lt;/li&gt;
&lt;li&gt;获取当前定位wx.getLocation权限配置&lt;/li&gt;
&lt;li&gt;后台持续定位配置要求&lt;/li&gt;
&lt;li&gt;设备信息、系统API获取&lt;/li&gt;
&lt;li&gt;振动、剪贴板、屏幕亮度API&lt;/li&gt;
&lt;li&gt;扫码wx.scanCode场景&lt;/li&gt;
&lt;li&gt;蓝牙BLE设备连接流程&lt;/li&gt;
&lt;li&gt;NFC基础使用场景&lt;/li&gt;
&lt;li&gt;相机camera组件适配&lt;/li&gt;
&lt;li&gt;文件管理FileSystemManager读写文件&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十性能优化专项&#34;&gt;十、性能优化专项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;setData性能优化手段&lt;/li&gt;
&lt;li&gt;长列表渲染优化方案&lt;/li&gt;
&lt;li&gt;虚拟列表实现思路&lt;/li&gt;
&lt;li&gt;分包加载优化首屏速度&lt;/li&gt;
&lt;li&gt;图片懒加载处理&lt;/li&gt;
&lt;li&gt;减少页面、组件层级嵌套&lt;/li&gt;
&lt;li&gt;wxss样式体积压缩优化&lt;/li&gt;
&lt;li&gt;分包预加载preloadRule配置&lt;/li&gt;
&lt;li&gt;避免频繁创建定时器、监听事件&lt;/li&gt;
&lt;li&gt;页面卸载清除所有订阅、定时器&lt;/li&gt;
&lt;li&gt;包体积超限优化方案&lt;/li&gt;
&lt;li&gt;开发者工具性能面板排查卡顿&lt;/li&gt;
&lt;li&gt;避免在onShow频繁请求接口&lt;/li&gt;
&lt;li&gt;图片资源压缩、webp适配&lt;/li&gt;
&lt;li&gt;减少observers深层监听开销&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十一适配兼容多端&#34;&gt;十一、适配、兼容、多端&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;rpx、px、rem转换关系&lt;/li&gt;
&lt;li&gt;刘海屏、安全区适配css写法&lt;/li&gt;
&lt;li&gt;深色模式适配配置&lt;/li&gt;
&lt;li&gt;不同微信版本API兼容处理&lt;/li&gt;
&lt;li&gt;caniuse判断接口是否可用&lt;/li&gt;
&lt;li&gt;小程序转H5、转uni-app差异&lt;/li&gt;
&lt;li&gt;平板、PC端小程序适配要点&lt;/li&gt;
&lt;li&gt;低版本微信兼容降级方案&lt;/li&gt;
&lt;li&gt;字体、图片多设备适配&lt;/li&gt;
&lt;li&gt;自定义导航栏适配胶囊按钮&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十二工程化第三方框架&#34;&gt;十二、工程化、第三方框架&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;原生小程序、uni-app、Taro区别&lt;/li&gt;
&lt;li&gt;Taro编译原理，多端适配逻辑&lt;/li&gt;
&lt;li&gt;uni-app分包、条件编译写法&lt;/li&gt;
&lt;li&gt;小程序npm依赖使用规则&lt;/li&gt;
&lt;li&gt;按需引入UI组件库优化&lt;/li&gt;
&lt;li&gt;工程化打包、环境变量区分&lt;/li&gt;
&lt;li&gt;多环境请求域名配置&lt;/li&gt;
&lt;li&gt;ESLint校验小程序代码规范&lt;/li&gt;
&lt;li&gt;Git协同开发规范&lt;/li&gt;
&lt;li&gt;CI自动上传小程序工具&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十三支付分享广告业务能力&#34;&gt;十三、支付、分享、广告、业务能力&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;小程序支付完整流程&lt;/li&gt;
&lt;li&gt;支付回调后端处理逻辑&lt;/li&gt;
&lt;li&gt;分享onShareAppMessage、onShareTimeline配置&lt;/li&gt;
&lt;li&gt;分享图、分享路径动态处理&lt;/li&gt;
&lt;li&gt;分享到朋友圈限制条件&lt;/li&gt;
&lt;li&gt;插屏广告、激励视频广告接入&lt;/li&gt;
&lt;li&gt;小程序跳转其他小程序API&lt;/li&gt;
&lt;li&gt;跳转限制与关联配置要求&lt;/li&gt;
&lt;li&gt;客服消息接入流程&lt;/li&gt;
&lt;li&gt;商品卡片、搜索收录配置sitemap&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十四安全审核合规&#34;&gt;十四、安全、审核、合规&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;小程序合法域名、业务域名、web-view域名区别&lt;/li&gt;
&lt;li&gt;前端存储敏感信息安全风险&lt;/li&gt;
&lt;li&gt;session_key不能传输到前端原因&lt;/li&gt;
&lt;li&gt;接口数据防篡改简单方案&lt;/li&gt;
&lt;li&gt;隐私合规要求有哪些&lt;/li&gt;
&lt;li&gt;图片、内容审核API调用&lt;/li&gt;
&lt;li&gt;小程序常见审核驳回原因&lt;/li&gt;
&lt;li&gt;诱导分享、诱导支付违规点&lt;/li&gt;
&lt;li&gt;本地存储数据加密思路&lt;/li&gt;
&lt;li&gt;防止恶意刷接口方案&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十五实战场景综合题&#34;&gt;十五、实战场景综合题&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;项目整体目录架构设计&lt;/li&gt;
&lt;li&gt;封装通用请求库完整思路&lt;/li&gt;
&lt;li&gt;全局登录拦截、未登录跳转实现&lt;/li&gt;
&lt;li&gt;大型表单组件封装与校验&lt;/li&gt;
&lt;li&gt;多页面共享登录状态管理&lt;/li&gt;
&lt;li&gt;列表上拉加载、下拉刷新封装&lt;/li&gt;
&lt;li&gt;图片上传、预览、删除完整流程&lt;/li&gt;
&lt;li&gt;分包改造解决主包体积超限&lt;/li&gt;
&lt;li&gt;页面返回保留搜索条件、分页数据&lt;/li&gt;
&lt;li&gt;小程序热更新主动检测逻辑&lt;/li&gt;
&lt;li&gt;websocket聊天断线重连方案&lt;/li&gt;
&lt;li&gt;自定义tabBar遇到的坑与解决&lt;/li&gt;
&lt;li&gt;页面大量数据滑动卡顿优化&lt;/li&gt;
&lt;li&gt;线上白屏、加载失败排查思路&lt;/li&gt;
&lt;li&gt;原生小程序迁移Taro/uni改造方案&lt;/li&gt;
&lt;/ol&gt;</description>
    </item>
    <item>
      <title>线性探测与链地址法的剖析</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/%E7%BA%BF%E6%80%A7%E6%8E%A2%E6%B5%8B%E4%B8%8E%E9%93%BE%E5%9C%B0%E5%9D%80%E6%B3%95%E7%9A%84%E6%B7%B1%E5%BA%A6%E5%89%96%E6%9E%90/</link>
      <pubDate>Sat, 11 Jul 2026 17:00:18 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/%E7%BA%BF%E6%80%A7%E6%8E%A2%E6%B5%8B%E4%B8%8E%E9%93%BE%E5%9C%B0%E5%9D%80%E6%B3%95%E7%9A%84%E6%B7%B1%E5%BA%A6%E5%89%96%E6%9E%90/</guid>
      <description>&lt;h2 id=&#34;为什么我们需要两种冲突解决策略&#34;&gt;为什么我们需要两种冲突解决策略？&lt;/h2&gt;
&lt;p&gt;哈希表的核心矛盾在于：&lt;strong&gt;哈希函数将无限的定义域映射到有限的地址空间&lt;/strong&gt;。根据鸽巢原理（Pigeonhole Principle），冲突是必然的。于是，计算机科学家们在&amp;quot;&lt;strong&gt;时间换空间&lt;/strong&gt;&amp;ldquo;和&amp;rdquo;&lt;strong&gt;空间换时间&lt;/strong&gt;&amp;ldquo;的永恒博弈中，诞生了两大流派：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;开放定址法（Open Addressing）&lt;/strong&gt;：所有元素都存储在数组本身，冲突时寻找其他空位——&lt;strong&gt;原地消化&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;链地址法（Separate Chaining）&lt;/strong&gt;：数组存储指针，冲突的元素在数组外形成链表——&lt;strong&gt;外部延展&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这两者看似只是实现细节的差异，实则反映了对&lt;strong&gt;内存模型、缓存行为、并发控制、最坏情况保证&lt;/strong&gt;等底层哲学的不同理解。&lt;/p&gt;
&lt;h2 id=&#34;一线性探测linear-probing极简主义的得与失&#34;&gt;一、线性探测（Linear Probing）：极简主义的得与失&lt;/h2&gt;
&lt;h3 id=&#34;11-算法精要&#34;&gt;1.1 算法精要&lt;/h3&gt;
&lt;p&gt;线性探测的规则极其简单：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;插入: h(k), h(k)+1, h(k)+2, ... (mod m)
查找: 同插入序列，直到找到或遇到空位
删除: 标记为&amp;#34;墓碑&amp;#34;(DELETED)，不能物理清空
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;关键洞察&lt;/strong&gt;：线性探测的查找路径是&lt;strong&gt;确定性的&lt;/strong&gt;，这意味着它拥有完美的CPU缓存预取特性（Prefetching），在现代CPU架构下，连续内存访问的速度比指针跳转快一个数量级。&lt;/p&gt;
&lt;h3 id=&#34;12-主聚集primary-clustering的数学本质&#34;&gt;1.2 主聚集（Primary Clustering）的数学本质&lt;/h3&gt;
&lt;p&gt;这是线性探测最致命的缺陷，也是理解其性能天花板的钥匙。&lt;/p&gt;
&lt;p&gt;假设负载因子为 α（α = n/m），当插入一个新元素时，它在某个位置发生冲突的概率不是简单的 α，而是&lt;strong&gt;该位置所在的连续占用块的长度占比&lt;/strong&gt;。这个正反馈机制导致：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一旦形成长度为 L 的连续占用块，新元素落入该块的概率为 L/m&lt;/li&gt;
&lt;li&gt;落入后，块长度变为 L+1，进一步增加未来冲突概率&lt;/li&gt;
&lt;li&gt;最终导致&lt;strong&gt;占用块像雪崩一样快速增长&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;数学结论&lt;/strong&gt;（Knuth 的经典分析）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;成功查找的平均探测次数 ≈ &lt;code&gt;0.5 * (1 + 1/(1-α))&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;插入的平均探测次数 ≈ &lt;code&gt;0.5 * (1 + 1/(1-α)^2)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当 α = 0.9 时，插入需要平均约 &lt;strong&gt;50.5 次&lt;/strong&gt;探测，性能崩溃。这也是为什么线性探测要求负载因子严格控制在 &lt;strong&gt;0.7 以下&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;13-删除与墓碑的隐藏代价&#34;&gt;1.3 删除与墓碑的隐藏代价&lt;/h3&gt;
&lt;p&gt;线性探测的删除必须使用墓碑，这带来三重悲剧：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;空间污染&lt;/strong&gt;：墓碑占用的位置无法被新数据直接覆盖（需要判断是否允许覆盖，复杂化逻辑）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;查询退化&lt;/strong&gt;：大量的墓碑会导致查找遍历过长的已删除序列&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;需要周期性重建&lt;/strong&gt;（Rehash）：当墓碑比例超过阈值（如 30%），需要重新插入所有存活元素&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 墓碑导致的查找效率下降示意
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ A ] [ &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;墓碑&lt;/span&gt; ] [ &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;墓碑&lt;/span&gt; ] [ &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;墓碑&lt;/span&gt; ] [ B ] [ &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;空&lt;/span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 查找 B：需要跳过 3 个墓碑，即使它们是空的，线性探测依然要检查
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;14-线性探测的真香场景&#34;&gt;1.4 线性探测的&amp;quot;真香&amp;quot;场景&lt;/h3&gt;
&lt;p&gt;尽管有上述缺陷，线性探测在工业界依然被广泛使用，原因在于：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Docker Healthcheck 万金油</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/docker-healthcheck-%E4%B8%87%E9%87%91%E6%B2%B9/</link>
      <pubDate>Sat, 11 Jul 2026 16:30:54 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/docker-healthcheck-%E4%B8%87%E9%87%91%E6%B2%B9/</guid>
      <description>&lt;h3 id=&#34;模板一网络服务万金油只要有网络端口通杀&#34;&gt;模板一：网络服务万金油（只要有网络端口，通杀）&lt;/h3&gt;
&lt;p&gt;如果容器是 Web 服务（如 Nginx、Tomcat、Node.js）、数据库（如 Redis、MySQL）或者各种中间件，只要它&lt;strong&gt;暴露了 TCP 端口&lt;/strong&gt;，且容器内带有最基础的 &lt;code&gt;sh&lt;/code&gt;，这就是最无敌的万金油配置。&lt;/p&gt;
&lt;p&gt;它利用了 Linux 内核原生 &lt;code&gt;&amp;lt;/dev/tcp&lt;/code&gt; 漏洞，完全不依赖 &lt;code&gt;curl&lt;/code&gt; 或 &lt;code&gt;wget&lt;/code&gt; 。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;healthcheck&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# 语法解释：尝试与容器本地的 8080 端口建立 TCP 连接，失败则退出码为 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;test&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CMD-SHELL&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sh -c &amp;#39;&amp;lt;/dev/tcp/127.0.0.1/8080&amp;#39; || exit 1&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;interval&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;10s&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# 10秒探一次，既保证敏锐度，又不会给系统带来TCP连接压力&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;timeout&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3s&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# 握手超过3秒没反应，说明网络栈或主线程已经卡死&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;retries&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# 连续失败3次（大约30秒内）正式宣判死刑&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;start_period&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;30s&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# 30秒新手保护期，给服务腾出启动和绑定端口的时间&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;注：使用时只需要把 &lt;code&gt;8080&lt;/code&gt; 改成你容器内部的实际端口（如 Redis 改成 6379，Nacos 改成 8848）即可。&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;模板二javaspring-boot-专属万金油解决高-cpu-与-full-gc-假死&#34;&gt;模板二：Java/Spring Boot 专属万金油（解决高 CPU 与 Full GC 假死）&lt;/h3&gt;
&lt;p&gt;对于 Java 应用，有时候端口虽然勉强能连上，但实际上 JVM 内部因为内存溢出（OOM）或者恐怖的 CPU 占用，已经完全无法处理业务了。&lt;/p&gt;
&lt;p&gt;这时候用 Java 自带的诊断工具 &lt;code&gt;jcmd&lt;/code&gt; 去拍 JVM 的脑袋，是最精准的万金油手段（前提是使用 JDK 镜像，非精简的 JRE）。&lt;/p&gt;</description>
    </item>
    <item>
      <title>JAVA程序员防翻车指南</title>
      <link>https://lv-blog.pages.dev/posts/programming/java%E7%A8%8B%E5%BA%8F%E5%91%98%E9%98%B2%E7%BF%BB%E8%BD%A6%E6%8C%87%E5%8D%97/</link>
      <pubDate>Thu, 09 Jul 2026 22:15:46 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/java%E7%A8%8B%E5%BA%8F%E5%91%98%E9%98%B2%E7%BF%BB%E8%BD%A6%E6%8C%87%E5%8D%97/</guid>
      <description>&lt;h2 id=&#34;一基础类型与字面量1-10&#34;&gt;一、基础类型与字面量（1-10）&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;int&lt;/code&gt; 最大值 &lt;code&gt;2,147,483,647&lt;/code&gt;（2³¹-1），最小值 &lt;code&gt;-2,147,483,648&lt;/code&gt;（-2³¹）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;long&lt;/code&gt; 最大值 &lt;code&gt;9,223,372,036,854,775,807&lt;/code&gt;（2⁶³-1），字面量加 &lt;code&gt;L&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;float&lt;/code&gt; 字面量必须加 &lt;code&gt;f&lt;/code&gt;，否则默认 &lt;code&gt;double&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;short&lt;/code&gt; 范围 &lt;code&gt;-32,768 ~ 32,767&lt;/code&gt;，&lt;code&gt;byte&lt;/code&gt; 范围 &lt;code&gt;-128 ~ 127&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;字面量下划线：&lt;code&gt;1_000_000&lt;/code&gt; 等于 &lt;code&gt;1000000&lt;/code&gt;，仅 Java 7+&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0x&lt;/code&gt; 开头是十六进制，&lt;code&gt;0b&lt;/code&gt; 开头是二进制，&lt;code&gt;0&lt;/code&gt; 开头是八进制（容易误判）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;char&lt;/code&gt; 占 2 字节，&lt;code&gt;Character.SIZE&lt;/code&gt; = 16，但 Unicode 扩展字符需 2 个 char（surrogate pair）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;boolean&lt;/code&gt; 只有 &lt;code&gt;true/false&lt;/code&gt;，不能和 0/1 互转（和 C 不同）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Integer.valueOf(127) == Integer.valueOf(127)&lt;/code&gt; 为 &lt;code&gt;true&lt;/code&gt;，&lt;code&gt;128&lt;/code&gt; 为 &lt;code&gt;false&lt;/code&gt;（缓存池 -128~127）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Integer.parseInt(&amp;quot;&amp;quot;)&lt;/code&gt; 抛 &lt;code&gt;NumberFormatException&lt;/code&gt;，&lt;code&gt;Integer.parseInt(null)&lt;/code&gt; 也抛&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;二运算符与表达式11-18&#34;&gt;二、运算符与表达式（11-18）&lt;/h2&gt;
&lt;ol start=&#34;11&#34;&gt;
&lt;li&gt;&lt;code&gt;&amp;amp;&lt;/code&gt; 和 &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; 区别：&lt;code&gt;&amp;amp;&lt;/code&gt; 两边都执行（位运算或逻辑与），&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; 短路&lt;/li&gt;
&lt;li&gt;&lt;code&gt;|&lt;/code&gt; 和 &lt;code&gt;||&lt;/code&gt; 同理，&lt;code&gt;||&lt;/code&gt; 短路&lt;/li&gt;
&lt;li&gt;&lt;code&gt;^&lt;/code&gt; 按位异或，&lt;code&gt;~&lt;/code&gt; 按位取反（包含符号位）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; 算术右移（补符号位），&lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt; 无符号右移（补 0）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i++&lt;/code&gt; 和 &lt;code&gt;++i&lt;/code&gt; 的字节码区别：前者先加载后自增，后者先自增后加载&lt;/li&gt;
&lt;li&gt;&lt;code&gt;+=&lt;/code&gt; 隐式类型转换：&lt;code&gt;short s = 1; s += 1;&lt;/code&gt; 合法，&lt;code&gt;s = s + 1;&lt;/code&gt; 编译错误&lt;/li&gt;
&lt;li&gt;三元运算符 &lt;code&gt;? :&lt;/code&gt; 必须返回相同类型，否则自动类型提升&lt;/li&gt;
&lt;li&gt;字符串拼接用 &lt;code&gt;+&lt;/code&gt; 在循环内会生成大量 &lt;code&gt;StringBuilder&lt;/code&gt;，循环外编译器自动优化&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;三string-相关19-28&#34;&gt;三、String 相关（19-28）&lt;/h2&gt;
&lt;ol start=&#34;19&#34;&gt;
&lt;li&gt;&lt;code&gt;String&lt;/code&gt; 不可变，底层 &lt;code&gt;char[]&lt;/code&gt; 被 &lt;code&gt;final&lt;/code&gt; 修饰且不暴露修改方法&lt;/li&gt;
&lt;li&gt;字符串常量池在堆中（Java 8+），&lt;code&gt;intern()&lt;/code&gt; 手动入池&lt;/li&gt;
&lt;li&gt;&lt;code&gt;new String(&amp;quot;abc&amp;quot;)&lt;/code&gt; 创建 2 个对象（常量池 + 堆），&lt;code&gt;&amp;quot;abc&amp;quot;&lt;/code&gt; 只创建 1 个（若池中没有）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;String.equals()&lt;/code&gt; 比较内容，&lt;code&gt;==&lt;/code&gt; 比较引用地址&lt;/li&gt;
&lt;li&gt;&lt;code&gt;String.compareTo()&lt;/code&gt; 按字典序比较，返回差值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;String.format()&lt;/code&gt; 使用 &lt;code&gt;%s&lt;/code&gt; &lt;code&gt;%d&lt;/code&gt; &lt;code&gt;%f&lt;/code&gt; 占位符&lt;/li&gt;
&lt;li&gt;&lt;code&gt;substring()&lt;/code&gt; 在 Java 7 前共享 &lt;code&gt;char[]&lt;/code&gt;，Java 7+ 创建新数组（解决内存泄漏）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;split()&lt;/code&gt; 参数是正则，&lt;code&gt;.&lt;/code&gt; 需转义为 &lt;code&gt;\\.&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;replace()&lt;/code&gt; 替换所有字符，&lt;code&gt;replaceAll()&lt;/code&gt; 支持正则&lt;/li&gt;
&lt;li&gt;&lt;code&gt;StringBuilder&lt;/code&gt; 线程不安全，&lt;code&gt;StringBuffer&lt;/code&gt; 线程安全（方法加 &lt;code&gt;synchronized&lt;/code&gt;），但慢&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;四equals-与-hashcode29-34&#34;&gt;四、equals 与 hashCode（29-34）&lt;/h2&gt;
&lt;ol start=&#34;29&#34;&gt;
&lt;li&gt;重写 &lt;code&gt;equals&lt;/code&gt; 必须重写 &lt;code&gt;hashCode&lt;/code&gt;，否则 &lt;code&gt;HashMap&lt;/code&gt;/&lt;code&gt;HashSet&lt;/code&gt; 失效&lt;/li&gt;
&lt;li&gt;&lt;code&gt;equals&lt;/code&gt; 必须满足：自反、对称、传递、一致、非空（&lt;code&gt;x.equals(null)&lt;/code&gt; 返回 &lt;code&gt;false&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hashCode&lt;/code&gt; 相等的两个对象 &lt;code&gt;equals&lt;/code&gt; 不一定相等（哈希冲突）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Objects.equals(a, b)&lt;/code&gt; 自动判空，避免 &lt;code&gt;null.equals()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Arrays.deepEquals()&lt;/code&gt; 比较多维数组，&lt;code&gt;Arrays.equals()&lt;/code&gt; 只比较一维&lt;/li&gt;
&lt;li&gt;&lt;code&gt;List.equals()&lt;/code&gt; 要求顺序相同，&lt;code&gt;Set.equals()&lt;/code&gt; 仅要求元素相同（顺序无关）&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;五异常处理35-44&#34;&gt;五、异常处理（35-44）&lt;/h2&gt;
&lt;ol start=&#34;35&#34;&gt;
&lt;li&gt;&lt;code&gt;try-catch-finally&lt;/code&gt; 中 &lt;code&gt;finally&lt;/code&gt; 在 &lt;code&gt;return&lt;/code&gt; 之前执行，但返回值已在 &lt;code&gt;finally&lt;/code&gt; 前计算好&lt;/li&gt;
&lt;li&gt;&lt;code&gt;finally&lt;/code&gt; 中有 &lt;code&gt;return&lt;/code&gt; 会覆盖 &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt; 的返回值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;finally&lt;/code&gt; 中修改返回的引用对象内容会生效（如 &lt;code&gt;List.add()&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;不要在 &lt;code&gt;finally&lt;/code&gt; 中写 &lt;code&gt;return&lt;/code&gt;，也不要在其中抛出异常（会掩盖原始异常）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;try-with-resources&lt;/code&gt; 要求资源实现 &lt;code&gt;AutoCloseable&lt;/code&gt;，关闭顺序：先声明的后关闭&lt;/li&gt;
&lt;li&gt;受检异常（&lt;code&gt;Exception&lt;/code&gt; 子类）必须 &lt;code&gt;try-catch&lt;/code&gt; 或 &lt;code&gt;throws&lt;/code&gt;，&lt;code&gt;RuntimeException&lt;/code&gt; 非受检&lt;/li&gt;
&lt;li&gt;异常链：&lt;code&gt;catch (SQLException e) { throw new RuntimeException(e); }&lt;/code&gt; 保留堆栈&lt;/li&gt;
&lt;li&gt;&lt;code&gt;printStackTrace()&lt;/code&gt; 不应用在生产日志中，用 &lt;code&gt;log.error(&amp;quot;msg&amp;quot;, e)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Throwable&lt;/code&gt; 包括 &lt;code&gt;Error&lt;/code&gt; 和 &lt;code&gt;Exception&lt;/code&gt;，&lt;code&gt;Error&lt;/code&gt; 不应该捕获（如 &lt;code&gt;OutOfMemoryError&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;finally&lt;/code&gt; 中关闭资源时可能抛异常，要用 &lt;code&gt;try-catch&lt;/code&gt; 包裹或使用 &lt;code&gt;try-with-resources&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;六集合框架45-62&#34;&gt;六、集合框架（45-62）&lt;/h2&gt;
&lt;ol start=&#34;45&#34;&gt;
&lt;li&gt;&lt;code&gt;ArrayList&lt;/code&gt; 初始容量 10，扩容 1.5 倍（&lt;code&gt;oldCapacity + (oldCapacity &amp;gt;&amp;gt; 1)&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ArrayList&lt;/code&gt; 随机访问 O(1)，中间插入删除 O(n)，&lt;code&gt;LinkedList&lt;/code&gt; 相反&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LinkedList&lt;/code&gt; 实现了 &lt;code&gt;Deque&lt;/code&gt;，可作为队列/栈使用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HashMap&lt;/code&gt; 容量为 2 的幂，默认 16，负载因子 0.75，扩容 2 倍&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HashMap&lt;/code&gt; 索引计算：&lt;code&gt;(n - 1) &amp;amp; hash&lt;/code&gt;，&lt;code&gt;hash = key.hashCode() ^ (h &amp;gt;&amp;gt;&amp;gt; 16)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Java 8+ &lt;code&gt;HashMap&lt;/code&gt; 链表长度 &amp;gt; 8 且容量 &amp;gt;= 64 时转红黑树，&amp;lt; 6 时退化为链表&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HashMap&lt;/code&gt; 的 &lt;code&gt;key&lt;/code&gt; 为 &lt;code&gt;null&lt;/code&gt; 时，hash 值为 0，存在 &lt;code&gt;table[0]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ConcurrentHashMap&lt;/code&gt; 分段锁（Java 7）→ &lt;code&gt;synchronized&lt;/code&gt; + CAS（Java 8+）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Hashtable&lt;/code&gt; 线程安全但全表锁，已淘汰&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TreeMap&lt;/code&gt; 基于红黑树，有序（按 key 自然序或 Comparator）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LinkedHashMap&lt;/code&gt; 按插入顺序或访问顺序（&lt;code&gt;accessOrder=true&lt;/code&gt; 可实现 LRU）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HashSet&lt;/code&gt; 底层是 &lt;code&gt;HashMap&lt;/code&gt;，&lt;code&gt;TreeSet&lt;/code&gt; 底层是 &lt;code&gt;TreeMap&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PriorityQueue&lt;/code&gt; 小顶堆，&lt;code&gt;Comparator.reverseOrder()&lt;/code&gt; 可转大顶堆&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ArrayDeque&lt;/code&gt; 优于 &lt;code&gt;Stack&lt;/code&gt;（&lt;code&gt;Stack&lt;/code&gt; 已废弃，&lt;code&gt;ArrayDeque&lt;/code&gt; 线程不安全但更快）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Collections.synchronizedList()&lt;/code&gt; 包装为线程安全，但迭代时仍需手动同步&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CopyOnWriteArrayList&lt;/code&gt; 读多写少场景，写时复制整个数组&lt;/li&gt;
&lt;li&gt;&lt;code&gt;List.of()&lt;/code&gt; / &lt;code&gt;Set.of()&lt;/code&gt;（Java 9+）返回不可变集合，不能增删改&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ArrayList.subList()&lt;/code&gt; 返回视图，对子列表操作会影响原列表，反之亦然&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;七并发与线程63-80&#34;&gt;七、并发与线程（63-80）&lt;/h2&gt;
&lt;ol start=&#34;63&#34;&gt;
&lt;li&gt;创建线程的三种方式：&lt;code&gt;Thread&lt;/code&gt;、&lt;code&gt;Runnable&lt;/code&gt;、&lt;code&gt;Callable&lt;/code&gt;（有返回值）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;start()&lt;/code&gt; 启动线程，&lt;code&gt;run()&lt;/code&gt; 只是普通方法调用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;synchronized&lt;/code&gt; 可锁实例方法、静态方法（锁 Class）、代码块&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wait()&lt;/code&gt; 释放锁，&lt;code&gt;sleep()&lt;/code&gt; 不释放锁，&lt;code&gt;yield()&lt;/code&gt; 让出 CPU 但不释放锁&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wait()&lt;/code&gt;/&lt;code&gt;notify()&lt;/code&gt; 必须在 &lt;code&gt;synchronized&lt;/code&gt; 块中调用，否则抛 &lt;code&gt;IllegalMonitorStateException&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;notify()&lt;/code&gt; 随机唤醒一个，&lt;code&gt;notifyAll()&lt;/code&gt; 唤醒全部&lt;/li&gt;
&lt;li&gt;死锁四条件：互斥、请求与保持、不可抢占、循环等待&lt;/li&gt;
&lt;li&gt;破坏死锁：按固定顺序加锁、&lt;code&gt;tryLock()&lt;/code&gt; 超时、使用 &lt;code&gt;ReentrantLock&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;volatile&lt;/code&gt; 保证可见性和有序性（禁止指令重排），不保证原子性&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AtomicInteger&lt;/code&gt; 用 CAS 实现原子操作，&lt;code&gt;incrementAndGet()&lt;/code&gt; 底层是 &lt;code&gt;Unsafe.compareAndSwapInt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ThreadLocal&lt;/code&gt; 用完后必须 &lt;code&gt;remove()&lt;/code&gt;，否则线程池复用导致内存泄漏&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ThreadLocal&lt;/code&gt; 底层是 &lt;code&gt;ThreadLocalMap&lt;/code&gt;，key 是弱引用，value 是强引用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ExecutorService&lt;/code&gt; 用 &lt;code&gt;shutdown()&lt;/code&gt; 优雅关闭，&lt;code&gt;shutdownNow()&lt;/code&gt; 立即关闭&lt;/li&gt;
&lt;li&gt;线程池核心参数：核心线程数、最大线程数、存活时间、阻塞队列、拒绝策略&lt;/li&gt;
&lt;li&gt;四种拒绝策略：&lt;code&gt;AbortPolicy&lt;/code&gt;（抛异常）、&lt;code&gt;CallerRunsPolicy&lt;/code&gt;（调用者执行）、&lt;code&gt;DiscardPolicy&lt;/code&gt;（丢弃）、&lt;code&gt;DiscardOldestPolicy&lt;/code&gt;（丢弃最旧）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CachedThreadPool&lt;/code&gt; 最大线程数 &lt;code&gt;Integer.MAX_VALUE&lt;/code&gt;，容易 OOM，慎用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FixedThreadPool&lt;/code&gt; 使用无界队列，任务积压可能导致 OOM&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Future.get()&lt;/code&gt; 阻塞，&lt;code&gt;CompletableFuture&lt;/code&gt; 异步回调更灵活&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;八io-与-nio81-88&#34;&gt;八、I/O 与 NIO（81-88）&lt;/h2&gt;
&lt;ol start=&#34;81&#34;&gt;
&lt;li&gt;&lt;code&gt;File&lt;/code&gt; 只是路径抽象，不表示真实文件，&lt;code&gt;exists()&lt;/code&gt; 判断是否存在&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FileInputStream&lt;/code&gt; 读取字节，&lt;code&gt;FileReader&lt;/code&gt; 读取字符（默认编码可能乱码）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BufferedReader&lt;/code&gt; 用 &lt;code&gt;readLine()&lt;/code&gt; 按行读取，&lt;code&gt;Files.readAllLines()&lt;/code&gt; 更简洁&lt;/li&gt;
&lt;li&gt;&lt;code&gt;InputStreamReader&lt;/code&gt; 可指定字符集：&lt;code&gt;new InputStreamReader(new FileInputStream(&amp;quot;a.txt&amp;quot;), StandardCharsets.UTF_8)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;try-with-resources&lt;/code&gt; 自动关闭多个资源，用分号分隔&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Path&lt;/code&gt;/&lt;code&gt;Paths&lt;/code&gt;/&lt;code&gt;Files&lt;/code&gt;（Java 7+）替代 &lt;code&gt;File&lt;/code&gt;，&lt;code&gt;Files.walk()&lt;/code&gt; 遍历目录树&lt;/li&gt;
&lt;li&gt;NIO 核心：&lt;code&gt;Channel&lt;/code&gt; + &lt;code&gt;Buffer&lt;/code&gt; + &lt;code&gt;Selector&lt;/code&gt;（多路复用）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ByteBuffer&lt;/code&gt; 读写切换需调用 &lt;code&gt;flip()&lt;/code&gt;，&lt;code&gt;clear()&lt;/code&gt; 清空，&lt;code&gt;compact()&lt;/code&gt; 压缩&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;九jvm-与内存89-95&#34;&gt;九、JVM 与内存（89-95）&lt;/h2&gt;
&lt;ol start=&#34;89&#34;&gt;
&lt;li&gt;JVM 内存区域：堆、栈、方法区（元空间）、程序计数器、本地方法栈&lt;/li&gt;
&lt;li&gt;堆分代：年轻代（Eden + S0 + S1）→ 老年代，默认比例 8:1:1&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OutOfMemoryError&lt;/code&gt; 常见原因：堆 OOM、元空间 OOM、直接内存 OOM、栈溢出&lt;/li&gt;
&lt;li&gt;栈溢出 &lt;code&gt;StackOverflowError&lt;/code&gt;，递归过深或无终止条件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;System.gc()&lt;/code&gt; 仅建议 GC，不保证执行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;finalize()&lt;/code&gt; 已废弃（Java 9+），对象自救不靠谱&lt;/li&gt;
&lt;li&gt;类加载器：Bootstrap（rt.jar）→ Extension → Application，双亲委派模型&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十日期与时间96-100&#34;&gt;十、日期与时间（96-100）&lt;/h2&gt;
&lt;ol start=&#34;96&#34;&gt;
&lt;li&gt;&lt;code&gt;java.util.Date&lt;/code&gt; 可变、线程不安全，已废弃，用 &lt;code&gt;java.time.*&lt;/code&gt;（Java 8+）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LocalDate&lt;/code&gt; / &lt;code&gt;LocalTime&lt;/code&gt; / &lt;code&gt;LocalDateTime&lt;/code&gt; 不含时区，&lt;code&gt;ZonedDateTime&lt;/code&gt; 含时区&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Instant&lt;/code&gt; 时间戳（秒/纳秒），&lt;code&gt;Duration&lt;/code&gt; 计算时间差，&lt;code&gt;Period&lt;/code&gt; 计算日期差&lt;/li&gt;
&lt;li&gt;格式化用 &lt;code&gt;DateTimeFormatter&lt;/code&gt; 线程安全，替代 &lt;code&gt;SimpleDateFormat&lt;/code&gt;（线程不安全）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LocalDateTime.now()&lt;/code&gt; 获取当前时间，&lt;code&gt;parse(&amp;quot;2026-07-09&amp;quot;)&lt;/code&gt; 按 ISO 标准解析&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十一语法糖与常见坑101-110&#34;&gt;十一、语法糖与常见坑（101-110）&lt;/h2&gt;
&lt;ol start=&#34;101&#34;&gt;
&lt;li&gt;泛型编译期擦除，运行时无泛型信息（&lt;code&gt;List&amp;lt;String&amp;gt;&lt;/code&gt; 和 &lt;code&gt;List&amp;lt;Integer&amp;gt;&lt;/code&gt; 在运行时相同）&lt;/li&gt;
&lt;li&gt;可变参数本质是数组，&lt;code&gt;public void method(String... args)&lt;/code&gt; 可传数组或逗号分隔&lt;/li&gt;
&lt;li&gt;枚举 &lt;code&gt;enum&lt;/code&gt; 默认继承 &lt;code&gt;Enum&lt;/code&gt;，不能被继承，构造器私有&lt;/li&gt;
&lt;li&gt;匿名内部类持有外部类引用（&lt;code&gt;this$0&lt;/code&gt;），可能导致内存泄漏&lt;/li&gt;
&lt;li&gt;接口默认方法 &lt;code&gt;default&lt;/code&gt;，静态方法 &lt;code&gt;static&lt;/code&gt;，接口中变量默认 &lt;code&gt;public static final&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;抽象类可有构造器，接口无构造器&lt;/li&gt;
&lt;li&gt;&lt;code&gt;switch&lt;/code&gt; 支持 &lt;code&gt;byte&lt;/code&gt;/&lt;code&gt;short&lt;/code&gt;/&lt;code&gt;char&lt;/code&gt;/&lt;code&gt;int&lt;/code&gt;/&lt;code&gt;String&lt;/code&gt;/&lt;code&gt;enum&lt;/code&gt;，不支持 &lt;code&gt;long&lt;/code&gt;/&lt;code&gt;float&lt;/code&gt;/&lt;code&gt;double&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;break&lt;/code&gt; 跳出循环，&lt;code&gt;continue&lt;/code&gt; 跳过本次，&lt;code&gt;return&lt;/code&gt; 结束方法&lt;/li&gt;
&lt;li&gt;标签 &lt;code&gt;label:&lt;/code&gt; 可跳出外层循环，但不推荐使用&lt;/li&gt;
&lt;li&gt;数组协变：&lt;code&gt;String[]&lt;/code&gt; 是 &lt;code&gt;Object[]&lt;/code&gt; 的子类，但集合泛型不变&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十二网络与反射111-118&#34;&gt;十二、网络与反射（111-118）&lt;/h2&gt;
&lt;ol start=&#34;111&#34;&gt;
&lt;li&gt;&lt;code&gt;URL&lt;/code&gt; 和 &lt;code&gt;URI&lt;/code&gt; 区别：URI 是标识符，URL 是定位符（包含协议）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HttpURLConnection&lt;/code&gt; 原生 HTTP 客户端，但 Apache HttpClient / OkHttp 更常用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Socket&lt;/code&gt; 阻塞 I/O，&lt;code&gt;ServerSocket&lt;/code&gt; 监听端口，&lt;code&gt;accept()&lt;/code&gt; 阻塞等待连接&lt;/li&gt;
&lt;li&gt;反射 &lt;code&gt;Class.forName()&lt;/code&gt; 初始化类，&lt;code&gt;ClassLoader.loadClass()&lt;/code&gt; 不初始化&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Method.invoke()&lt;/code&gt; 性能差，但反射能绕过私有访问（&lt;code&gt;setAccessible(true)&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Proxy.newProxyInstance()&lt;/code&gt; 动态代理只能代理接口，CGLIB 可代理类&lt;/li&gt;
&lt;li&gt;注解保留策略：&lt;code&gt;SOURCE&lt;/code&gt;（源码）、&lt;code&gt;CLASS&lt;/code&gt;（字节码）、&lt;code&gt;RUNTIME&lt;/code&gt;（运行时）&lt;/li&gt;
&lt;li&gt;序列化实现 &lt;code&gt;Serializable&lt;/code&gt; 接口，&lt;code&gt;serialVersionUID&lt;/code&gt; 用于版本兼容，不声明则自动生成&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十三设计原则与模式119-123&#34;&gt;十三、设计原则与模式（119-123）&lt;/h2&gt;
&lt;ol start=&#34;119&#34;&gt;
&lt;li&gt;单例双重检查需 &lt;code&gt;volatile&lt;/code&gt;，防止指令重排导致半初始化对象被读取&lt;/li&gt;
&lt;li&gt;工厂模式解耦，策略模式消除 if-else，观察者模式事件驱动&lt;/li&gt;
&lt;li&gt;依赖倒置：依赖抽象而非具体实现&lt;/li&gt;
&lt;li&gt;开闭原则：对扩展开放，对修改封闭&lt;/li&gt;
&lt;li&gt;里氏替换：子类可以替换父类出现的地方&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十四linux-与常用命令124-128&#34;&gt;十四、Linux 与常用命令（124-128）&lt;/h2&gt;
&lt;ol start=&#34;124&#34;&gt;
&lt;li&gt;&lt;code&gt;nohup java -jar app.jar &amp;amp;&lt;/code&gt; 后台运行，输出到 &lt;code&gt;nohup.out&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jps&lt;/code&gt; 查看 Java 进程，&lt;code&gt;jstack&lt;/code&gt; 打印线程堆栈，&lt;code&gt;jmap&lt;/code&gt; 查看堆内存，&lt;code&gt;jstat&lt;/code&gt; 监控 GC&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kill -15&lt;/code&gt; 优雅关闭（SIGTERM），&lt;code&gt;kill -9&lt;/code&gt; 强制杀死（SIGKILL）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tail -f app.log&lt;/code&gt; 实时查看日志，&lt;code&gt;grep -C 10 &amp;quot;error&amp;quot; app.log&lt;/code&gt; 显示上下文&lt;/li&gt;
&lt;li&gt;&lt;code&gt;netstat -tlnp&lt;/code&gt; 查看端口占用，&lt;code&gt;lsof -i:8080&lt;/code&gt; 查看指定端口&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十五数据库与-jdbc129-133&#34;&gt;十五、数据库与 JDBC（129-133）&lt;/h2&gt;
&lt;ol start=&#34;129&#34;&gt;
&lt;li&gt;&lt;code&gt;PreparedStatement&lt;/code&gt; 防 SQL 注入，占位符 &lt;code&gt;?&lt;/code&gt;，编译一次执行多次&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Statement&lt;/code&gt; 拼接字符串有注入风险，不用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ResultSet&lt;/code&gt; 游标从 1 开始，&lt;code&gt;next()&lt;/code&gt; 移动指针，&lt;code&gt;getString(1)&lt;/code&gt; 按索引取&lt;/li&gt;
&lt;li&gt;事务隔离级别：读未提交、读已提交、可重复读、串行化&lt;/li&gt;
&lt;li&gt;连接池用 HikariCP（默认）、Druid，不要手动创建连接&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十六maven--gradle134-137&#34;&gt;十六、Maven / Gradle（134-137）&lt;/h2&gt;
&lt;ol start=&#34;134&#34;&gt;
&lt;li&gt;Maven 生命周期：&lt;code&gt;clean&lt;/code&gt; → &lt;code&gt;compile&lt;/code&gt; → &lt;code&gt;test&lt;/code&gt; → &lt;code&gt;package&lt;/code&gt; → &lt;code&gt;install&lt;/code&gt; → &lt;code&gt;deploy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;provided&lt;/code&gt; 作用域表示运行时由容器提供（如 servlet-api）&lt;/li&gt;
&lt;li&gt;依赖传递：&lt;code&gt;compile&lt;/code&gt; 传递，&lt;code&gt;test&lt;/code&gt; 不传递，&lt;code&gt;provided&lt;/code&gt; 不传递&lt;/li&gt;
&lt;li&gt;版本冲突用 &lt;code&gt;dependencyManagement&lt;/code&gt; 锁定版本，或用 &lt;code&gt;exclude&lt;/code&gt; 排除&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十七工具与调试138-142&#34;&gt;十七、工具与调试（138-142）&lt;/h2&gt;
&lt;ol start=&#34;138&#34;&gt;
&lt;li&gt;&lt;code&gt;System.out.println()&lt;/code&gt; 性能差，生产用日志框架（SLF4J + Logback）&lt;/li&gt;
&lt;li&gt;日志级别：ERROR &amp;gt; WARN &amp;gt; INFO &amp;gt; DEBUG &amp;gt; TRACE&lt;/li&gt;
&lt;li&gt;&lt;code&gt;assert&lt;/code&gt; 默认禁用，需 &lt;code&gt;-ea&lt;/code&gt; 开启，生产慎用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Objects.requireNonNull()&lt;/code&gt; 判空抛 &lt;code&gt;NullPointerException&lt;/code&gt;，比手动 &lt;code&gt;if&lt;/code&gt; 简洁&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Optional&lt;/code&gt; 用来表示可能为 null 的返回值，不要用作字段或参数&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;十八编码规范与常识143-150&#34;&gt;十八、编码规范与常识（143-150）&lt;/h2&gt;
&lt;ol start=&#34;143&#34;&gt;
&lt;li&gt;包名全小写，类名大驼峰，方法/变量小驼峰，常量全大写 + 下划线&lt;/li&gt;
&lt;li&gt;方法名用动词（&lt;code&gt;getUser&lt;/code&gt;），变量名用名词（&lt;code&gt;userName&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;布尔变量用 &lt;code&gt;is&lt;/code&gt; / &lt;code&gt;has&lt;/code&gt; / &lt;code&gt;can&lt;/code&gt; 开头（&lt;code&gt;isDeleted&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;一个 &lt;code&gt;.java&lt;/code&gt; 文件只能有一个 &lt;code&gt;public&lt;/code&gt; 类，文件名必须和 &lt;code&gt;public&lt;/code&gt; 类名一致&lt;/li&gt;
&lt;li&gt;构造器不能 &lt;code&gt;static&lt;/code&gt;，不能被 &lt;code&gt;final&lt;/code&gt; 修饰&lt;/li&gt;
&lt;li&gt;&lt;code&gt;static&lt;/code&gt; 块在类加载时执行一次，&lt;code&gt;{}&lt;/code&gt; 实例块在构造器前执行&lt;/li&gt;
&lt;li&gt;匿名对象（&lt;code&gt;new User()&lt;/code&gt;）用完即抛，适合单次使用&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;永远不要在线上环境用 &lt;code&gt;System.out&lt;/code&gt; 打印大对象，更不要用 &lt;code&gt;e.printStackTrace()&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;</description>
    </item>
    <item>
      <title>漫谈AI上下文长度</title>
      <link>https://lv-blog.pages.dev/posts/programming/ai/%E6%BC%AB%E8%B0%88ai%E4%B8%8A%E4%B8%8B%E6%96%87%E9%95%BF%E5%BA%A6/</link>
      <pubDate>Thu, 09 Jul 2026 20:58:34 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/ai/%E6%BC%AB%E8%B0%88ai%E4%B8%8A%E4%B8%8B%E6%96%87%E9%95%BF%E5%BA%A6/</guid>
      <description>&lt;pre class=&#34;mermaid&#34;&gt;flowchart TD
    A[2018–2021&lt;br/&gt;512–2K Token&lt;br/&gt;金鱼记忆时代] --&gt;|只能处理短文、短句、单轮问答| B[2022–2023&lt;br/&gt;4K–128K Token&lt;br/&gt;中上下文普及时代]
    B --&gt;|可处理论文、合同、小说、中型代码库&lt;br/&gt;RAG 成为企业标准方案| C[2024–2025&lt;br/&gt;200K–1M Token&lt;br/&gt;百万上下文实验期]
    C --&gt;|纸面支持 1M，但遗忘、成本、速度问题明显&lt;br/&gt;仅限量 Beta| D[2026–2027&lt;br/&gt;1M–2M Token&lt;br/&gt;1M 量产普惠时代]
    D --&gt;|1M 成为旗舰标配&lt;br/&gt;可处理整卷宗、整代码库、全年业务日志| E[2028–2029&lt;br/&gt;2M–10M Token&lt;br/&gt;超百万窗口分化时代]
    E --&gt;|2M 以上面向行业定制&lt;br/&gt;长视频、大型代码库、多年日志联合分析| F[2030+&lt;br/&gt;10M+ 弹性记忆&lt;br/&gt;原生长记忆智能体时代]
&lt;/pre&gt;
&lt;h1 id=&#34;一大模型上下文完整进化时间线20182026分4个时代&#34;&gt;一、大模型上下文完整进化时间线（2018–2026，分4个时代）&lt;/h1&gt;
&lt;h2 id=&#34;1-初代transformer时代5122k20182021金鱼记忆&#34;&gt;1. 初代Transformer时代：512–2K（2018–2021，金鱼记忆）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;2018 GPT-1 / BERT：&lt;strong&gt;512 token&lt;/strong&gt;，仅短文、短句分类，多轮对话必丢前文&lt;/li&gt;
&lt;li&gt;2019 GPT-2：&lt;strong&gt;1024 token&lt;/strong&gt;，能写短篇故事，连续对话3–5轮就遗忘历史&lt;/li&gt;
&lt;li&gt;2020 GPT-3：&lt;strong&gt;2048 token（2K）&lt;/strong&gt;，行业通用标准，仅支持短提示词、少量示例，长文档必须分段/摘要处理&lt;/li&gt;
&lt;li&gt;2021 早期国产（文心一言初代、GLM-1）：统一2K上限，无长文本能力&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;时代特征&lt;/strong&gt;：没有原生长文本能力，所有长内容必须靠人工拆分、外部摘要，RAG雏形出现。&lt;/p&gt;
&lt;h2 id=&#34;2-中上下文普及时代4k128k20222023工业化可用&#34;&gt;2. 中上下文普及时代：4K–128K（2022–2023，工业化可用）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;2022 ChatGPT（GPT-3.5）：&lt;strong&gt;4K&lt;/strong&gt;；年末升级16K，日常聊天够用，长文档仍吃力&lt;/li&gt;
&lt;li&gt;2023.3 GPT-4 首发：&lt;strong&gt;8K&lt;/strong&gt;，专业文档、代码单文件处理门槛打开&lt;/li&gt;
&lt;li&gt;2023.7 Claude 2：&lt;strong&gt;100K&lt;/strong&gt;，首个量产十万级窗口，法律、长篇论文场景爆发&lt;/li&gt;
&lt;li&gt;2023.11 GPT-4 Turbo：&lt;strong&gt;128K&lt;/strong&gt;，全球主流商用标配门槛，单本小说完整载入&lt;/li&gt;
&lt;li&gt;2023年底 国产跟进：通义、GLM、混元开放32K/64K；开源Llama 2、Qwen 7B固定4K–32K&lt;/li&gt;
&lt;li&gt;2023.12 Gemini 1.0 Ultra 纸面宣称1M，但仅实验室封闭测试，无法商用落地&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;时代里程碑&lt;/strong&gt;：128K成为专业AI标配；RAG成为行业标准方案，弥补窗口不足。&lt;/p&gt;
&lt;h2 id=&#34;3-百万上下文实验期200k2m纸面20242025纸面强实际弱&#34;&gt;3. 百万上下文实验期：200K–2M纸面（2024–2025，纸面强、实际弱）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;2024.2 Gemini 1.5 Pro：&lt;strong&gt;原生2M token&lt;/strong&gt;，全球首个公开百万级模型，但存在严重「中间遗忘Lost in the Middle」，后半段文档召回暴跌，仅适合摘要，不适合精细推理，仅限开发者限量Beta&lt;/li&gt;
&lt;li&gt;2024 Claude 3 Opus：&lt;strong&gt;200K&lt;/strong&gt;，稳定可靠，法律行业主力，无严重遗忘问题&lt;/li&gt;
&lt;li&gt;2025 上半年：各大厂商放出1M Beta（Claude Sonnet 4、Gemini 2.0），长上下文计费溢价极高、响应慢、显存开销巨大，企业少量试用，普通用户无法接触&lt;/li&gt;
&lt;li&gt;2025 国产开源：Qwen、DeepSeek推出64K–128K底座，少量实验版支持256K&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;时代特征&lt;/strong&gt;：1M只是技术噱头，&lt;strong&gt;标称≠有效&lt;/strong&gt;；硬件成本、遗忘问题、价格三重门槛，无法大规模落地。&lt;/p&gt;</description>
    </item>
    <item>
      <title>一个程序员应该知道的各种锁</title>
      <link>https://lv-blog.pages.dev/posts/programming/%E4%B8%80%E4%B8%AA%E7%A8%8B%E5%BA%8F%E5%91%98%E5%BA%94%E8%AF%A5%E7%9F%A5%E9%81%93%E7%9A%84%E5%90%84%E7%A7%8D%E9%94%81/</link>
      <pubDate>Thu, 09 Jul 2026 11:15:34 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/%E4%B8%80%E4%B8%AA%E7%A8%8B%E5%BA%8F%E5%91%98%E5%BA%94%E8%AF%A5%E7%9F%A5%E9%81%93%E7%9A%84%E5%90%84%E7%A7%8D%E9%94%81/</guid>
      <description>&lt;h3 id=&#34;1-悲观锁-vs-乐观锁心态问题&#34;&gt;1. 悲观锁 vs 乐观锁（心态问题）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;悲观锁&lt;/strong&gt;：觉得肯定有人抢厕所，进去就&lt;strong&gt;反锁门&lt;/strong&gt;（加锁），用完再开。&lt;br&gt;
→ Java里的 &lt;code&gt;synchronized&lt;/code&gt; 和 &lt;code&gt;ReentrantLock&lt;/code&gt; 都是这种。&lt;strong&gt;安全，但慢&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;乐观锁&lt;/strong&gt;：觉得没人抢，不锁门，但上厕所时&lt;strong&gt;盯着门把手&lt;/strong&gt;（版本号/时间戳），如果发现被人动过（冲突），就重试。&lt;br&gt;
→ Java里的 &lt;strong&gt;CAS（比较并交换）&lt;/strong&gt; 就是这种，比如 &lt;code&gt;AtomicInteger&lt;/code&gt;。&lt;strong&gt;快，但冲突多时会反复重试&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&#34;2-公平锁-vs-非公平锁排队问题&#34;&gt;2. 公平锁 vs 非公平锁（排队问题）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;公平锁&lt;/strong&gt;：先来后到，乖乖排队。&lt;br&gt;
→ &lt;code&gt;new ReentrantLock(true)&lt;/code&gt;。&lt;strong&gt;公平，但效率低&lt;/strong&gt;（大家都得排队）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;非公平锁&lt;/strong&gt;：新来的可以&lt;strong&gt;插队&lt;/strong&gt;，如果锁刚好释放，它就直接抢。&lt;br&gt;
→ &lt;code&gt;synchronized&lt;/code&gt; 和默认的 &lt;code&gt;ReentrantLock&lt;/code&gt; 都是非公平。&lt;strong&gt;效率高，但可能导致某些线程饿死&lt;/strong&gt;（一直抢不到）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&#34;3-可重入锁同一个人的多次进入&#34;&gt;3. 可重入锁（同一个人的多次进入）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;你进了厕所A，发现里面还有个小隔间B，你&lt;strong&gt;能直接进B&lt;/strong&gt;，不用再掏钥匙。&lt;br&gt;
→ &lt;code&gt;synchronized&lt;/code&gt; 和 &lt;code&gt;ReentrantLock&lt;/code&gt; 都支持。&lt;strong&gt;同一个线程可以多次获取同一把锁&lt;/strong&gt;，防止自己把自己卡死。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&#34;4-读写锁分情况管理&#34;&gt;4. 读写锁（分情况管理）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;厕所分&lt;strong&gt;蹲位（写锁）&lt;strong&gt;和&lt;/strong&gt;洗手池（读锁）&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;多人同时洗手（读）没问题。&lt;/li&gt;
&lt;li&gt;但有人蹲坑（写）时，别人既不能蹲也不能洗手（全阻塞）。&lt;br&gt;
→ &lt;code&gt;ReentrantReadWriteLock&lt;/code&gt;。&lt;strong&gt;适合读多写少&lt;/strong&gt;的场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&#34;5-共享锁-vs-排他锁权限级别&#34;&gt;5. 共享锁 vs 排他锁（权限级别）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;排他锁（写锁）&lt;/strong&gt;：厕所门一锁，谁也别进。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;共享锁（读锁）&lt;/strong&gt;：可以多人同时看同一份文件（但不能改）。&lt;br&gt;
→ 读写锁就是共享/排他的典型实现。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&#34;6-偏向锁--轻量级锁--重量级锁锁升级jvm自动优化&#34;&gt;6. 偏向锁 → 轻量级锁 → 重量级锁（锁升级，JVM自动优化）&lt;/h3&gt;
&lt;p&gt;这是 &lt;code&gt;synchronized&lt;/code&gt; 的底层升级过程（为了性能）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;偏向锁&lt;/strong&gt;：厕所只认你一个人，你每次来都不用掏钥匙（无竞争）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;轻量级锁&lt;/strong&gt;：偶尔有别人来，你们用“自旋”方式（原地转圈等）抢，不挂起线程（省资源）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重量级锁&lt;/strong&gt;：竞争激烈，排队挂起（操作系统介入，慢）。&lt;br&gt;
→ 这是JVM自动做的，&lt;strong&gt;你不用管&lt;/strong&gt;，但知道它存在即可。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&#34;7-自旋锁不睡觉死等&#34;&gt;7. 自旋锁（不睡觉，死等）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;厕所被占，你不去排队睡觉，而是&lt;strong&gt;在门口原地转圈&lt;/strong&gt;（循环检查），等它释放。&lt;br&gt;
→ 适合&lt;strong&gt;持有锁时间很短&lt;/strong&gt;的情况，避免线程挂起/唤醒的开销。Java里的 &lt;code&gt;CAS&lt;/code&gt; 就是自旋思想。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&#34;8-分段锁分块管理&#34;&gt;8. 分段锁（分块管理）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;一个大厕所分成多个小隔间，锁只锁其中一间，不影响其他间。&lt;br&gt;
→ &lt;code&gt;ConcurrentHashMap&lt;/code&gt; 早期就是用分段锁，提升并发度（现在改用CAS+细粒度锁了）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&#34;一张图总结按使用场景选&#34;&gt;一张图总结（按使用场景选）：&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;场景&lt;/th&gt;
					&lt;th&gt;推荐锁&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;简单同步，代码少&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;synchronized&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;需要可中断、超时、公平等灵活功能&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;ReentrantLock&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;读多写少（如缓存）&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;ReentrantReadWriteLock&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;计数器、自增等简单操作&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;AtomicXXX&lt;/code&gt;（乐观锁）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;追求极致性能，竞争不激烈&lt;/td&gt;
					&lt;td&gt;偏向锁/轻量级锁（JVM自动）&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;</description>
    </item>
    <item>
      <title>Docker 常用配置</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/code-snippets/docker-%E5%B8%B8%E7%94%A8%E9%85%8D%E7%BD%AE/</link>
      <pubDate>Thu, 09 Jul 2026 11:04:37 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/code-snippets/docker-%E5%B8%B8%E7%94%A8%E9%85%8D%E7%BD%AE/</guid>
      <description>&lt;h2 id=&#34;kafka&#34;&gt;Kafka&lt;/h2&gt;
&lt;h3 id=&#34;kafdrop&#34;&gt;Kafdrop&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;services&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;kafdrop&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;obsidiandynamics/kafdrop&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;kafdrop&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9000:9000&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;KAFKA_BROKERCONNECT&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;localhost:9092&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;SERVER_SERVLET_CONTEXTPATH&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;unless-stopped&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;kraft-模式&#34;&gt;KRaft 模式&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;services&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;kafka&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;apache/kafka:3.9.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;kafka&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;hostname&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;kafka&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9092:9092&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;KAFKA_NODE_ID&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;KAFKA_PROCESS_ROLES&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;broker,controller&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;KAFKA_CONTROLLER_QUORUM_VOTERS&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;@&lt;span style=&#34;color:#ae81ff&#34;&gt;kafka:9093&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# 注意：这里不要换行，不要逗号&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;KAFKA_LISTENERS&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;PLAINTEXT://:9092,CONTROLLER://:9093&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# 外部访问地址&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;KAFKA_ADVERTISED_LISTENERS&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;PLAINTEXT://localhost:9092&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;KAFKA_LISTENER_SECURITY_PROTOCOL_MAP&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;KAFKA_CONTROLLER_LISTENER_NAMES&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;CONTROLLER&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;KAFKA_INTER_BROKER_LISTENER_NAME&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;PLAINTEXT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;KAFKA_TRANSACTION_STATE_LOG_MIN_ISR&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;CLUSTER_ID&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;MkU3OEVBNTcwNTJENDM2Qk&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;./data:/var/lib/kafka/data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;unless-stopped&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Java GC 是如何驱赶“老年群体”的</title>
      <link>https://lv-blog.pages.dev/posts/programming/why-why-why/java-gc%E6%98%AF%E5%A6%82%E4%BD%95%E9%A9%B1%E8%B5%B6%E8%80%81%E5%B9%B4%E5%AF%B9%E8%B1%A1%E7%9A%84/</link>
      <pubDate>Thu, 09 Jul 2026 10:19:20 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/why-why-why/java-gc%E6%98%AF%E5%A6%82%E4%BD%95%E9%A9%B1%E8%B5%B6%E8%80%81%E5%B9%B4%E5%AF%B9%E8%B1%A1%E7%9A%84/</guid>
      <description>&lt;p&gt;在 Java 的世界里，&lt;strong&gt;“分代年龄”（Age）&lt;/strong&gt; 是专门为 JVM 垃圾回收（GC）设计的一个&lt;strong&gt;计数器&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;简单来说，它记录了&lt;strong&gt;一个 Java 对象在垃圾回收中活过了多少轮&lt;/strong&gt;。就像打游戏刷副本一样，对象每在垃圾回收的“清洗”中幸存下来一次，它的分代年龄就会 &lt;strong&gt;+1&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;1-为什么需要分代年龄&#34;&gt;1. 为什么需要“分代年龄”？&lt;/h2&gt;
&lt;p&gt;这源于 Java 垃圾回收领域著名的 &lt;strong&gt;弱分代假说（Weak Generational Hypothesis）&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;绝大多数的 Java 对象都是“朝生夕死”的。&lt;/strong&gt; 比如你在一个方法里 new 了一个局部变量，方法结束了，这个对象就没用了。但也有极少数对象（如 Spring 的 Bean、数据库连接池）会一直存活。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;为了高效管理内存，JVM 把堆内存分成了两大区域：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;新生代（Young Generation）：&lt;/strong&gt; 存放刚出生、寿命短的对象。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;老年代（Old Generation）：&lt;/strong&gt; 存放寿命长、常驻内存的对象。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;“分代年龄”就是对象从“新生代”晋升到“老年代”的资格证和进度条。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;2-它的工作流程是怎样的&#34;&gt;2. 它的工作流程是怎样的？&lt;/h2&gt;
&lt;p&gt;我们可以把新生代想象成一个“新手村”，老年代想象成“满级主城”：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;出生（0岁）：&lt;/strong&gt; 绝大多数新对象在新生代的 &lt;strong&gt;Eden（伊甸园）区&lt;/strong&gt; 出生。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;第一次渡劫（1岁）：&lt;/strong&gt; 发生了一次 Minor GC（新生代垃圾回收）。如果这个对象没被回收，它会幸存下来，被移动到 &lt;strong&gt;Survivor（幸存者）区&lt;/strong&gt;，同时它的分代年龄变成 &lt;strong&gt;1 岁&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;继续熬资历（每活过一轮 +1岁）：&lt;/strong&gt; 以后每发生一次 Minor GC，只要它还在幸存者区折腾且没死掉，它的年龄就会加 1 岁。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;晋升老年代：&lt;/strong&gt; 当它的年龄达到一定阈值（&lt;strong&gt;默认是 15 岁&lt;/strong&gt;，由 JVM 参数 &lt;code&gt;-XX:MaxTenuringThreshold&lt;/code&gt; 决定）时，JVM 就会认为：“这小伙子挺能活，应该是个核心常驻对象。” 于是把它&lt;strong&gt;晋升（Promote）到老年代&lt;/strong&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;3-它存在对象的什么地方&#34;&gt;3. 它存在对象的什么地方？&lt;/h2&gt;
&lt;p&gt;正如我们在讨论“锁”时提到的，分代年龄存在于每个 Java 对象的 &lt;strong&gt;对象头（Object Header）的 Mark Word&lt;/strong&gt; 里面。&lt;/p&gt;</description>
    </item>
    <item>
      <title>为什么每个java对象都有锁的属性？这样不是浪费内存吗</title>
      <link>https://lv-blog.pages.dev/posts/programming/why-why-why/%E4%B8%BA%E4%BB%80%E4%B9%88%E6%AF%8F%E4%B8%AAjava%E5%AF%B9%E8%B1%A1%E9%83%BD%E6%9C%89%E9%94%81%E7%9A%84%E5%B1%9E%E6%80%A7%E8%BF%99%E6%A0%B7%E4%B8%8D%E6%98%AF%E6%B5%AA%E8%B4%B9%E5%86%85%E5%AD%98%E5%90%97/</link>
      <pubDate>Thu, 09 Jul 2026 10:11:43 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/why-why-why/%E4%B8%BA%E4%BB%80%E4%B9%88%E6%AF%8F%E4%B8%AAjava%E5%AF%B9%E8%B1%A1%E9%83%BD%E6%9C%89%E9%94%81%E7%9A%84%E5%B1%9E%E6%80%A7%E8%BF%99%E6%A0%B7%E4%B8%8D%E6%98%AF%E6%B5%AA%E8%B4%B9%E5%86%85%E5%AD%98%E5%90%97/</guid>
      <description>&lt;h2 id=&#34;1-为什么当初要这样设计设计初衷&#34;&gt;1. 为什么当初要这样设计？（设计初衷）&lt;/h2&gt;
&lt;p&gt;Java 诞生于 20 世纪 90 年代中期，当时多线程编程（并发）正在兴起。Java 的设计者高斯林（James Gosling）希望 Java 成为一门简单易用的多线程语言。&lt;/p&gt;
&lt;h3 id=&#34;简化并发编程&#34;&gt;简化并发编程&lt;/h3&gt;
&lt;p&gt;如果对象没有内置锁，你每次想给一段代码加锁，都必须显式地创建一个 &lt;code&gt;Lock&lt;/code&gt; 对象：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 如果没有内置锁，你得这么写：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Lock myLock &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ReentrantLock();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doSomething&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    myLock.&lt;span style=&#34;color:#a6e22e&#34;&gt;lock&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 业务逻辑&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;finally&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        myLock.&lt;span style=&#34;color:#a6e22e&#34;&gt;unlock&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;而 Java 设计者引入了 &lt;code&gt;synchronized&lt;/code&gt; 关键字，直接让对象充当锁，把复杂的同步简化成了：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 极简的同步写法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;synchronized&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 业务逻辑&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;“万物皆对象，万物皆可为锁”的设计，让开发者不需要管理一堆乱七八糟的锁对象，只要拿到目标对象，就能直接进行同步控制。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;2-这样不浪费内存吗jvm-是怎么偷懒的&#34;&gt;2. 这样不浪费内存吗？JVM 是怎么“偷懒”的？&lt;/h2&gt;
&lt;p&gt;你担心的内存浪费，JVM 工程师早就想到了。他们绝对不会傻到给每个刚 new 出来的对象都分配一个沉重的操作系统级别的锁（Monitor）。&lt;/p&gt;
&lt;p&gt;JVM 解决这个问题的核心思路是：&lt;strong&gt;按需分配，动态升级。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&#34;秘密武器对象头object-header&#34;&gt;秘密武器：对象头（Object Header）&lt;/h3&gt;
&lt;p&gt;在 Java 中，每个对象的内存结构里都有一个叫 &lt;strong&gt;Mark Word（标记字）&lt;/strong&gt; 的区域（在 64 位虚拟机上占 &lt;strong&gt;8 个字节 / 64 位&lt;/strong&gt;）。&lt;/p&gt;</description>
    </item>
    <item>
      <title>H mod C = H &amp; (C - 1) ?</title>
      <link>https://lv-blog.pages.dev/posts/programming/why-why-why/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%A6%82%E4%BD%95%E6%B1%82%E6%A8%A1/</link>
      <pubDate>Wed, 08 Jul 2026 17:38:40 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/why-why-why/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%A6%82%E4%BD%95%E6%B1%82%E6%A8%A1/</guid>
      <description>&lt;p&gt;在 Java 后端开发面试或源码阅读中，&lt;code&gt;HashMap&lt;/code&gt; 永远是避不开的核心。很多人能熟练地背出它的扩容阈值、红黑树化条件，但当深入到源码底层，看到诸如 &lt;code&gt;e.hash &amp;amp; (newCap - 1)&lt;/code&gt; 和 &lt;code&gt;e.hash &amp;amp; oldCap&lt;/code&gt; 这样的位运算时，往往会陷入沉思。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一-起源为什么数组长度必须是-2-的次幂&#34;&gt;一、 起源：为什么数组长度必须是 2 的次幂？&lt;/h2&gt;
&lt;p&gt;在散列表中，为了让数据均匀分布，最直观的想法是对哈希值进行&lt;strong&gt;取模（求余数）&lt;/strong&gt;：&lt;/p&gt;
$$\text{索引位置} = \text{hash} \pmod{\text{Capacity}}$$&lt;p&gt;然而，在 CPU 的底层底层执行中，&lt;strong&gt;除法和取模（%）是非常昂贵的算术操作&lt;/strong&gt;（可能需要几十个时钟周期）。为了追求极致的性能，底层的数论定理为我们提供了一个完美的替代方案：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;数学定理&lt;/strong&gt;：当容量 $C$ 是 $2$ 的次幂（$2^n$）时，对于任意整数 $H$，满足：&lt;/p&gt;
$$H \pmod C \equiv H \ \&amp; \ (C - 1)$$&lt;/blockquote&gt;
&lt;p&gt;位运算（&lt;code&gt;&amp;amp;&lt;/code&gt;）在 CPU 中只需要 &lt;strong&gt;1 个时钟周期&lt;/strong&gt;！为了享受到这个性能红利，HashMap 在源码中将容量死死限制为 2 的次幂：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 默认初始容量 16 (2的4次方)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; DEFAULT_INITIAL_CAPACITY &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 1 &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; 4;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;裁剪器的魔术hash--newcap---1&#34;&gt;裁剪器的魔术：&lt;code&gt;hash &amp;amp; (newCap - 1)&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;以容量 &lt;code&gt;16&lt;/code&gt; 为例，&lt;code&gt;16 - 1 = 15&lt;/code&gt;（二进制：&lt;code&gt;0000 1111&lt;/code&gt;）。任何 Hash 值与 &lt;code&gt;15&lt;/code&gt; 进行 &lt;code&gt;&amp;amp;&lt;/code&gt; 运算，高位都会被无情“抹零”，只有最后 4 位被保留下来：&lt;/p&gt;</description>
    </item>
    <item>
      <title>限流降级研究笔记</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/%E9%99%90%E6%B5%81%E9%99%8D%E7%BA%A7%E7%A0%94%E7%A9%B6%E7%AC%94%E8%AE%B0/</link>
      <pubDate>Tue, 07 Jul 2026 16:05:10 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/%E9%99%90%E6%B5%81%E9%99%8D%E7%BA%A7%E7%A0%94%E7%A9%B6%E7%AC%94%E8%AE%B0/</guid>
      <description>&lt;h2 id=&#34;主流算法&#34;&gt;主流算法&lt;/h2&gt;
&lt;h3 id=&#34;固定窗口计数器&#34;&gt;固定窗口计数器&lt;/h3&gt;
&lt;p&gt;每秒一个计数器，+1超过阈值就拒绝&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;缺点&lt;/strong&gt; 0.51s 和 1.51s 之间产生2倍流量&lt;/p&gt;
&lt;h3 id=&#34;滑动窗口&#34;&gt;滑动窗口&lt;/h3&gt;
&lt;p&gt;把时间切成更细的小格，滑动统计&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;缺点&lt;/strong&gt; 解决临界问题，但是实现复杂&lt;/p&gt;
&lt;h3 id=&#34;漏桶&#34;&gt;漏桶&lt;/h3&gt;
&lt;p&gt;请求进桶，匀速流出，桶满则弃&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;缺点&lt;/strong&gt;流出速度恒定，扛不了正常的突发&lt;/p&gt;
&lt;h3 id=&#34;令牌桶&#34;&gt;令牌桶&lt;/h3&gt;
&lt;p&gt;匀速往桶里放令牌，来请求拿令牌，没令牌被拒绝&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;缺点&lt;/strong&gt;允许一定突发&lt;/p&gt;</description>
    </item>
    <item>
      <title>Java 从Random理解 CAS自旋模式</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/understanding-cas-spin-from-random/</link>
      <pubDate>Sat, 06 Jun 2026 21:40:20 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/understanding-cas-spin-from-random/</guid>
      <description>&lt;p&gt;你理解这段代码吗？&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    oldseed &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; seed.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    newseed &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (oldseed &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; ...) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; mask;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;seed.&lt;span style=&#34;color:#a6e22e&#34;&gt;compareAndSet&lt;/span&gt;(oldseed, newseed));   &lt;span style=&#34;color:#75715e&#34;&gt;// ← CAS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;第层先搞懂变量在多线程里的危险&#34;&gt;第〇层：先搞懂&amp;quot;变量&amp;quot;在多线程里的危险&lt;/h2&gt;
&lt;p&gt;假设有一个变量 &lt;code&gt;seed = 100&lt;/code&gt;，两个线程&lt;strong&gt;同时&lt;/strong&gt;想改它：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;线程A：读到 seed=100 → 算出新值 200 → 写回 seed=200
线程B：读到 seed=100 → 算出新值 300 → 写回 seed=300
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;问题来了——两个人都读到了 100，各算各的，最后谁写得晚谁赢。A 的结果被 B 覆盖了，A 白干了，而且&lt;strong&gt;程序根本不知道出错了&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这就是经典的 &lt;strong&gt;线程安全问题&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;第一层解决办法有两条路&#34;&gt;第一层：解决办法有两条路&lt;/h2&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;路线一：悲观锁（synchronized）
  → &amp;#34;我先把门锁上，别人别进来&amp;#34;
  → 安全但慢（别人要排队）

路线二：乐观锁（CAS）
  → &amp;#34;门不锁，但我写之前验一下，被人改了我就重来&amp;#34;
  → 快但可能要重试
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;你这段代码走的就是 &lt;strong&gt;路线二&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;第二层什么是-cas&#34;&gt;第二层：什么是 CAS？&lt;/h2&gt;
&lt;p&gt;CAS = &lt;strong&gt;Compare And Set&lt;/strong&gt;（比较并设置），三个参数：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;CAS(内存地址, 我期望的旧值, 我想写入的新值)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;它做的事用大白话说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;我记得这个值是 42，如果现在&lt;strong&gt;还是&lt;/strong&gt; 42，就帮我改成 77。如果不是 42 了，说明有人动过了，啥也别干，告诉我失败了。&amp;rdquo;&lt;/p&gt;</description>
    </item>
    <item>
      <title>常见缓存策略精析</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/redis/common-cache-strategies/</link>
      <pubDate>Tue, 05 May 2026 22:46:44 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/redis/common-cache-strategies/</guid>
      <description>&lt;h1 id=&#34;缓存三兄弟&#34;&gt;缓存三兄弟&lt;/h1&gt;
&lt;h2 id=&#34;缓存穿透&#34;&gt;缓存穿透&lt;/h2&gt;
&lt;p&gt;是什么：大量请求查询数据库不存在的数据。缓存没有，持续击打数据库
防范方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;缓存空值
&lt;ol&gt;
&lt;li&gt;数据库查不到也往缓存放一个空标记（TTL短，2分钟，该TTL过期了才能进行再次数据库查询）&lt;/li&gt;
&lt;li&gt;下一次同样的id来了直接被挡住&lt;/li&gt;
&lt;li&gt;优点：有效拦截大量穿透请求&lt;/li&gt;
&lt;li&gt;缺点：
&lt;ol&gt;
&lt;li&gt;恶意攻击造成大量不同的不存在的key，缓存堆满无效数据，浪费内存&lt;/li&gt;
&lt;li&gt;延迟了数据一致性，新数据必须等缓存过期&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;布隆过滤器&lt;/strong&gt;（推荐）
&lt;ol&gt;
&lt;li&gt;启动时把所有合法id放入布隆过滤器；&lt;/li&gt;
&lt;li&gt;布隆过滤器不给进就真的没有；&lt;/li&gt;
&lt;li&gt;优点：
&lt;ol&gt;
&lt;li&gt;没有高内存占用风险&lt;/li&gt;
&lt;li&gt;没有数据一致性风险&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;缺点：
&lt;ol&gt;
&lt;li&gt;有极小误判率&lt;/li&gt;
&lt;li&gt;增删要维护。数据更新时，要同步更新布隆过滤器&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;接口层限流和校验
&lt;ol&gt;
&lt;li&gt;API网关或Controller层做拦截&lt;/li&gt;
&lt;li&gt;参数校验、限流降级&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;互斥锁重建
&lt;ol&gt;
&lt;li&gt;互斥锁主要解决缓存击穿（热点key过期），但是在缓存空对象场景下，如果有大量并发请求一个不存在的key，可以使用锁&lt;/li&gt;
&lt;li&gt;每次访问让一个线程去查DB，其他线程等待&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;大厂的实践&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;网关层 校验参数格式，IP限流（挡掉脚本攻击）&lt;/li&gt;
&lt;li&gt;过滤器层 布隆过滤器&lt;/li&gt;
&lt;li&gt;缓存层&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;缓存击穿&#34;&gt;缓存击穿&lt;/h2&gt;
&lt;p&gt;是什么：某个被疯狂访问的热点key，因为TTL一到，失效的一瞬间海量并发请求同时miss，同时到DB重建同一个key&lt;/p&gt;
&lt;p&gt;防范方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;互斥锁
&lt;ol&gt;
&lt;li&gt;只让第1个miss的线程去查DB&lt;/li&gt;
&lt;li&gt;其他线程等一下再读缓存
&lt;ol&gt;
&lt;li&gt;高一致性：线程傻傻等待&lt;/li&gt;
&lt;li&gt;低一致性：先给旧数据，下一次来查就是新的&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;逻辑过期
&lt;ol&gt;
&lt;li&gt;key永不物理过期，把过期时间存在value里面&lt;/li&gt;
&lt;li&gt;如果发现逻辑上过期了，异步开个线程重建&lt;/li&gt;
&lt;li&gt;当前请求先返回旧值&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;互斥锁的实现&#34;&gt;互斥锁的实现&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;如何搭建出正确的锁？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;v1：SETNX key 1 抢锁，DEL key 释放&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;SETNX=&amp;ldquo;不存在才设置成功&amp;rdquo;，天然互斥。但问题：抢到锁的线程崩了、DEL 没执行 → 锁永远不释放 → 死锁。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;v2：给锁加过期间&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;崩了也能自动过期。但关键：必须用一条原子命令 SET key value NX EX 30。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;陷阱：别写成 SETNX + 再 EXPIRE 两条——如果刚 SETNX 成功、还没 EXPIRE 就崩了，又变回 v1 的死锁。&amp;ldquo;抢锁&amp;quot;和&amp;quot;设过期&amp;quot;必须一步做完。&lt;/p&gt;</description>
    </item>
    <item>
      <title>构建一个聊天室需要的基础知识</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/fundamentals-for-building-a-chatroom/</link>
      <pubDate>Fri, 03 Apr 2026 11:45:26 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/fundamentals-for-building-a-chatroom/</guid>
      <description>&lt;h1 id=&#34;基础知识&#34;&gt;基础知识&lt;/h1&gt;
&lt;h2 id=&#34;tcp-三次握手&#34;&gt;TCP 三次握手&lt;/h2&gt;
&lt;p&gt;客户端 - 服务器&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;三次握手目的&lt;/strong&gt;：客户端的收发没问题，服务器的收发也没问题。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&#34;第一次握手客户端发-syn同步请求&#34;&gt;第一次握手：客户端发 SYN（同步请求）&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;客户端&lt;/strong&gt;：我啥也不知道，我发个 &lt;strong&gt;SYN&lt;/strong&gt; 消息出去，看看有没有人接收到。&lt;/li&gt;
&lt;li&gt;如果没人回复，我再发几次（超时重传）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;这个时刻，客户端知道的事实是&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;我发出去了，但不知道有没有人收到 ❌&lt;/li&gt;
&lt;li&gt;我能不能收消息？不知道 ❌&lt;/li&gt;
&lt;li&gt;对方存不存在？不知道 ❌&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h4 id=&#34;第二次握手服务器回-synack同步确认&#34;&gt;第二次握手：服务器回 SYN+ACK（同步+确认）&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;服务器&lt;/strong&gt;收到了客户端的 SYN。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;服务器回复 &lt;strong&gt;SYN+ACK&lt;/strong&gt;：“我收到你的消息了，我也发一条试试，看看你能不能收到。”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;这个时刻，服务器知道的事实是&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;客户端发消息是没有问题的 ✅（因为我收到了）&lt;/li&gt;
&lt;li&gt;服务器收消息是没有问题的 ✅（因为我收到了）&lt;/li&gt;
&lt;li&gt;服务器不知道服务器发消息有没有问题 ❌（我发出去了，但不知道对方收到没）&lt;/li&gt;
&lt;li&gt;服务器不知道客户端收消息有没有问题 ❌（我发出去了，但不知道对方收到没）&lt;/li&gt;
&lt;li&gt;服务器需要发送一条 SYN+ACK，等对方回复 ACK 来确认“我能发、对方能收”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;当客户端收到 SYN+ACK 后，客户端可以确定以下事实&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;我发消息是没有问题的 ✅（我发的 SYN 被收到了）&lt;/li&gt;
&lt;li&gt;我收消息也是没有问题的 ✅（我收到了对方的回复）&lt;/li&gt;
&lt;li&gt;服务器收消息是没有问题的 ✅（对方收到了我的 SYN）&lt;/li&gt;
&lt;li&gt;服务器发消息也是没有问题的 ✅（我收到了对方的 SYN+ACK）&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;客户端这边已经确认全双工通信没问题了！&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;但是服务器他还有顾虑（不知道自己能不能发、不知道我能不能收），我再发个 ACK 给他吧&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h4 id=&#34;第三次握手客户端发-ack确认&#34;&gt;第三次握手：客户端发 ACK（确认）&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;客户端&lt;/strong&gt;收到 SYN+ACK 后，回复一个 &lt;strong&gt;ACK&lt;/strong&gt;：“我收到你的 SYN+ACK 了，我这边收发都没问题，你也可以放心了。”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;当服务器收到这个 ACK 后，服务器可以确定以下事实&lt;/strong&gt;：&lt;/p&gt;</description>
    </item>
    <item>
      <title>为什么有时候后端需要维护一张Refresh_Tokens表</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/why-backend-maintains-a-refresh-tokens-table/</link>
      <pubDate>Mon, 02 Mar 2026 20:07:07 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/why-backend-maintains-a-refresh-tokens-table/</guid>
      <description>&lt;h1 id=&#34;正常-jwt-请求流程&#34;&gt;正常 JWT 请求流程&lt;/h1&gt;
&lt;pre class=&#34;mermaid&#34;&gt;sequenceDiagram
    participant User as 用户
    participant Frontend as 前端（浏览器/App）
    participant Auth as 认证服务器
    participant Backend as 后端API服务器

    Note over User,Backend: 1. 登录阶段
    User-&gt;&gt;Frontend: 输入用户名/密码
    Frontend-&gt;&gt;Auth: POST /login (凭证)
    Auth-&gt;&gt;Auth: 验证凭证
    Auth--&gt;&gt;Frontend: 返回 access_token + refresh_token
    Frontend-&gt;&gt;Frontend: 存储token（内存/localStorage）
    Frontend--&gt;&gt;User: 登录成功

    Note over User,Backend: 2. 正常请求阶段
    User-&gt;&gt;Frontend: 请求受保护资源
    Frontend-&gt;&gt;Backend: GET /api/resource&lt;br/&gt;Authorization: Bearer access_token
    Backend-&gt;&gt;Backend: 验证access_token签名和过期时间
    Backend--&gt;&gt;Frontend: 返回请求的资源
    Frontend--&gt;&gt;User: 展示数据

    Note over User,Backend: 3. Access Token过期
    User-&gt;&gt;Frontend: 继续请求
    Frontend-&gt;&gt;Backend: GET /api/resource&lt;br/&gt;Authorization: Bearer access_token(已过期)
    Backend--&gt;&gt;Frontend: 401 Unauthorized (token过期)
    Frontend-&gt;&gt;Frontend: 检测到401，触发刷新逻辑

    Note over Frontend,Auth: 4. 刷新Token阶段
    Frontend-&gt;&gt;Auth: POST /refresh&lt;br/&gt;refresh_token
    Auth-&gt;&gt;Auth: 验证refresh_token
    Auth--&gt;&gt;Frontend: 返回新的 access_token（可选的新refresh_token）
    Frontend-&gt;&gt;Frontend: 更新存储的access_token
    Frontend-&gt;&gt;Backend: 重试原请求（新access_token）
    Backend--&gt;&gt;Frontend: 返回请求的资源
    Frontend--&gt;&gt;User: 展示数据
&lt;/pre&gt;
&lt;h1 id=&#34;为什么不能只靠jwt&#34;&gt;为什么不能只靠JWT&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;refresh token 发出去后后端不保存，会变成 &lt;strong&gt;不可控的长期通行证&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;无法主动踢人下线&lt;/li&gt;
&lt;li&gt;无法注销单点设备&lt;/li&gt;
&lt;li&gt;无法判断 token 是否被盗用（攻击者拿到了 refresh token 可以一直刷新 access token）&lt;/li&gt;
&lt;li&gt;无法实现会话管理&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&#34;使用-refresh-tokens-表后的流程图&#34;&gt;使用 refresh tokens 表后的流程图&lt;/h1&gt;
&lt;pre class=&#34;mermaid&#34;&gt;sequenceDiagram
    participant User as 用户
    participant Frontend as 前端
    participant Auth as 认证服务器
    participant DB as 数据库(refresh_tokens表)
    participant Backend as 后端API服务器

    Note over User,DB: 1. 登录阶段（签发token + 入库）
    User-&gt;&gt;Frontend: 输入用户名/密码
    Frontend-&gt;&gt;Auth: POST /login
    Auth-&gt;&gt;Auth: 验证凭证
    Auth-&gt;&gt;DB: 生成唯一refresh_token_id&lt;br/&gt;INSERT INTO refresh_tokens&lt;br/&gt;(user_id, token_hash, expires_at,&lt;br/&gt; device_info, ip_address, revoked)
    DB--&gt;&gt;Auth: 插入成功
    Auth-&gt;&gt;Auth: 生成access_token + refresh_token&lt;br/&gt;(refresh_token包含id引用)
    Auth--&gt;&gt;Frontend: 返回access_token + refresh_token
    Frontend-&gt;&gt;Frontend: 存储token
    Frontend--&gt;&gt;User: 登录成功

    Note over User,Backend: 2. 正常请求（与之前相同）
    User-&gt;&gt;Frontend: 请求资源
    Frontend-&gt;&gt;Backend: GET /api/resource&lt;br/&gt;Authorization: Bearer access_token
    Backend-&gt;&gt;Backend: 验证access_token
    Backend--&gt;&gt;Frontend: 返回资源

    Note over Frontend,DB: 3. Access Token过期 → 刷新
    Frontend-&gt;&gt;Backend: GET /api/resource (access_token过期)
    Backend--&gt;&gt;Frontend: 401 Unauthorized
    Frontend-&gt;&gt;Auth: POST /refresh&lt;br/&gt;refresh_token

    Note over Auth,DB: 4. 刷新验证（多步校验）
    Auth-&gt;&gt;Auth: 解析refresh_token，提取token_id
    Auth-&gt;&gt;DB: SELECT * FROM refresh_tokens&lt;br/&gt;WHERE id = token_id
    DB--&gt;&gt;Auth: 返回记录
    
    Auth-&gt;&gt;Auth: 校验清单：
    Note over Auth: ✅ token_hash是否匹配&lt;br/&gt;✅ 是否过期 (expires_at &gt; now())&lt;br/&gt;✅ 是否被撤销 (revoked = false)&lt;br/&gt;✅ 用户是否仍有效&lt;br/&gt;✅ 设备信息是否一致（可选）
    
    alt 校验全部通过
        Auth-&gt;&gt;DB: UPDATE refresh_tokens&lt;br/&gt;SET last_used_at = now(),&lt;br/&gt;    last_used_ip = current_ip&lt;br/&gt;WHERE id = token_id
        Auth-&gt;&gt;Auth: 生成新access_token&lt;br/&gt;（可选：延长refresh_token有效期）
        Auth--&gt;&gt;Frontend: 返回新access_token
        Frontend-&gt;&gt;Frontend: 更新access_token
        Frontend-&gt;&gt;Backend: 重试原请求（新token）
        Backend--&gt;&gt;Frontend: 返回资源
    else 校验失败
        Auth--&gt;&gt;Frontend: 401/403 (刷新失败)
        Frontend-&gt;&gt;Frontend: 清除所有token
        Frontend-&gt;&gt;User: 跳转登录页
    end

    Note over User,DB: 5. 主动登出
    User-&gt;&gt;Frontend: 点击登出
    Frontend-&gt;&gt;Auth: POST /logout&lt;br/&gt;refresh_token
    Auth-&gt;&gt;DB: UPDATE refresh_tokens&lt;br/&gt;SET revoked = true&lt;br/&gt;WHERE id = token_id
    Auth--&gt;&gt;Frontend: 登出成功
    Frontend-&gt;&gt;Frontend: 清除本地token
    Frontend--&gt;&gt;User: 已登出

    Note over User,DB: 6. 安全场景：密码修改
    User-&gt;&gt;Frontend: 修改密码
    Frontend-&gt;&gt;Auth: POST /change-password
    Auth-&gt;&gt;DB: UPDATE refresh_tokens&lt;br/&gt;SET revoked = true&lt;br/&gt;WHERE user_id = current_user_id
    Note over DB: 撤销该用户所有refresh_token&lt;br/&gt;（强制所有设备重新登录）
    Auth--&gt;&gt;Frontend: 密码修改成功
    Frontend-&gt;&gt;Frontend: 清除本地token
    Frontend--&gt;&gt;User: 请重新登录
&lt;/pre&gt;</description>
    </item>
    <item>
      <title>微服务认证系统的架构梳理和面试应对</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/microservice-auth-architecture-and-interview/</link>
      <pubDate>Mon, 26 Jan 2026 18:05:16 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/microservice-auth-architecture-and-interview/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;技术栈&lt;/strong&gt;：Spring Boot 3 · Spring Cloud Alibaba · OpenFeign · JWT · Gateway · Nacos&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;如何使用这份文档&#34;&gt;如何使用这份文档&lt;/h2&gt;
&lt;p&gt;面试讲项目，最忌讳从代码细节讲起。正确顺序是：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;先讲它解决什么问题 → 再讲整体架构 → 然后按请求流程串一遍 → 最后应对深挖。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;本文档按这个顺序组织。带 🎤 标记的引用框，是可以基本照着说的话术。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一一句话概述开场用&#34;&gt;一、一句话概述（开场用）&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;🎤 我做了一套基于 Spring Cloud Alibaba 的微服务认证系统。它把「认证」这件事拆成三个角色：&lt;strong&gt;auth 服务负责签发令牌、网关负责统一校验令牌、各业务服务通过请求头拿到用户身份&lt;/strong&gt;。整体用 JWT 做无状态认证，服务之间用 OpenFeign 通信，靠 Nacos 做服务发现。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;关键词锚点&lt;/strong&gt;（面试官会顺着这些追问，要准备好）：无状态 JWT、网关统一鉴权、OpenFeign 远程调用、Nacos 服务发现、BCrypt 密码加密、职责分离。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二它解决什么问题讲动机&#34;&gt;二、它解决什么问题（讲动机）&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;背景&lt;/strong&gt;：系统是微服务架构，有多个独立服务（auth、user-service、archive-service 等）。如果每个服务各自做一遍登录校验，会有两个问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;重复&lt;/strong&gt;：每个服务都写一遍鉴权逻辑，改规则要改很多处。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;有状态难扩展&lt;/strong&gt;：传统 session 存在单台服务器内存里，多实例之间不共享，扩容困难。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;解决思路&lt;/strong&gt;：「网关统一安检 + JWT 无状态令牌」。所有请求先经过网关校验令牌，业务服务不再重复鉴权；令牌本身自包含用户信息，验证只需用密钥本地验签，不依赖服务端存储。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;🎤 类比机场：网关是安检口，严格查一次护照（验签）；过了安检给你贴个写着身份的手环（请求头里的用户 id）；后面登机口、免税店（各业务服务）只看手环，不再查护照。验签只做一次，业务服务零负担。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三整体架构讲骨架&#34;&gt;三、整体架构（讲骨架）&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;模块划分&lt;/strong&gt;：项目是 Maven 多模块微服务，核心模块及职责如下。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;模块&lt;/th&gt;
					&lt;th&gt;类型&lt;/th&gt;
					&lt;th&gt;职责&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;gateway&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;网关&lt;/td&gt;
					&lt;td&gt;所有请求入口；统一校验 JWT；按路由转发到后端服务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;auth&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;认证服务&lt;/td&gt;
					&lt;td&gt;登录、注册；验密码；签发 JWT。&lt;strong&gt;自己不连数据库&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;user-service&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;业务服务&lt;/td&gt;
					&lt;td&gt;管理用户数据（tb_user 表的增删改查）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;archive-service&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;业务服务&lt;/td&gt;
					&lt;td&gt;档案业务；从请求头读取当前用户身份&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;api&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;契约模块&lt;/td&gt;
					&lt;td&gt;存放各服务的 Feign 接口声明 + 配套 DTO（被各服务依赖）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;common&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;基建底座&lt;/td&gt;
					&lt;td&gt;统一返回 Result、全局配置、ThreadLocal 用户上下文等&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;一个关键设计——auth 与 user-service 分离&lt;/strong&gt;：auth 只管「认证动作」（验密码、发令牌），不碰数据库；它要用户数据时，通过 OpenFeign 远程调用 user-service 去查。user-service 只管「用户数据」，不掺和登录逻辑。&lt;/p&gt;</description>
    </item>
    <item>
      <title>说一说登录这件麻烦事</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/the-hassle-of-login/</link>
      <pubDate>Fri, 26 Dec 2025 15:56:40 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/the-hassle-of-login/</guid>
      <description>从手机验证码到 Passkey，聊聊登录背后那些没人愿意细想的麻烦，以及一套可落地的最佳实践。</description>
    </item>
    <item>
      <title>Spring Boot 常用代码片段</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/code-snippets/spring-boot-common-snippets/</link>
      <pubDate>Wed, 26 Nov 2025 09:51:37 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/code-snippets/spring-boot-common-snippets/</guid>
      <description>&lt;h1 id=&#34;通用&#34;&gt;通用&lt;/h1&gt;
&lt;h2 id=&#34;依赖管理&#34;&gt;依赖管理&lt;/h2&gt;
&lt;h3 id=&#34;父-pomxml-固定三版本管控&#34;&gt;父 pom.xml 固定三版本管控&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://lv-blog.pages.dev/posts/programming/backend/sca-springcloud-springboot-version-mapping/&#34;&gt;版本参考&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependencyManagement&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;!-- 1. SpringBoot 基础版本 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-dependencies&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.5.0&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;type&amp;gt;&lt;/span&gt;pom&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;import&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;!-- 2. Spring Cloud 云原生基础 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-dependencies&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2025.0.0&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;type&amp;gt;&lt;/span&gt;pom&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;import&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;!-- 3. Spring Cloud Alibaba 阿里全套依赖核心（关键！） --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.alibaba.cloud&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-alibaba-dependencies&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2025.0.0.0&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;type&amp;gt;&lt;/span&gt;pom&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;import&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependencyManagement&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;启动类&#34;&gt;启动类&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@MapperScan&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;asia.liminality.user.mapper&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@SpringBootApplication&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@Slf4j&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;UserApplication&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;(String&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; args) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; UnknownHostException {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ConfigurableApplicationContext app &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; SpringApplication.&lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt;(UserApplication.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;, args);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Environment env &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; app.&lt;span style=&#34;color:#a6e22e&#34;&gt;getEnvironment&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        String protocol &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (env.&lt;span style=&#34;color:#a6e22e&#34;&gt;getProperty&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;server.ssl.key-store&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            protocol &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        log.&lt;span style=&#34;color:#a6e22e&#34;&gt;info&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;--/\n---------------------------------------------------------------------------------------\n\t&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Application &amp;#39;{}&amp;#39; is running! Access URLs:\n\t&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Local: \t\t{}://localhost:{}\n\t&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;External: \t{}://{}:{}\n\t&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Profile(s): \t{}&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\n---------------------------------------------------------------------------------------&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                env.&lt;span style=&#34;color:#a6e22e&#34;&gt;getProperty&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;spring.application.name&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                protocol,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                env.&lt;span style=&#34;color:#a6e22e&#34;&gt;getProperty&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;server.port&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                protocol,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                InetAddress.&lt;span style=&#34;color:#a6e22e&#34;&gt;getLocalHost&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;getHostAddress&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                env.&lt;span style=&#34;color:#a6e22e&#34;&gt;getProperty&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;server.port&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                env.&lt;span style=&#34;color:#a6e22e&#34;&gt;getActiveProfiles&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;domain&#34;&gt;domain&lt;/h2&gt;
&lt;h3 id=&#34;dto&#34;&gt;DTO&lt;/h3&gt;
&lt;h4 id=&#34;result&#34;&gt;Result&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; lombok.AllArgsConstructor;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; lombok.Data;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; lombok.NoArgsConstructor;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@Data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@NoArgsConstructor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@AllArgsConstructor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; code;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; String message;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; T data;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; Result&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;success&lt;/span&gt;(T data) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Result&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt;(200, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;success&amp;#34;&lt;/span&gt;, data);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; Result&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;success&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Result&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt;(200, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;success&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; Result&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;failure&lt;/span&gt;(String message) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Result&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt;(500, message, &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; Result&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;failure&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; code, String message) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Result&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt;(code, message, &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; Result&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;failure&lt;/span&gt;(String message, T data) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Result&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt;(500, message, data);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;spring-cloud-gateway&#34;&gt;Spring Cloud Gateway&lt;/h1&gt;
&lt;h2 id=&#34;authglobalfilter&#34;&gt;AuthGlobalFilter&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@Slf4j&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@RequiredArgsConstructor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@Component&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AuthGlobalFilter&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; GlobalFilter, Ordered {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; JwtUtil jwtUtil;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; List&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;String&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; WHITE_LIST &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; List.&lt;span style=&#34;color:#a6e22e&#34;&gt;of&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/auth/user/login&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/auth/user/register&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 判断是否在白名单内&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;isWhiteList&lt;/span&gt;(String path){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; WHITE_LIST.&lt;span style=&#34;color:#a6e22e&#34;&gt;stream&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;anyMatch&lt;/span&gt;(path::startsWith);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Mono&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Void&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;reject&lt;/span&gt;(ServerWebExchange exchange){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        exchange.&lt;span style=&#34;color:#a6e22e&#34;&gt;getResponse&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;setStatusCode&lt;/span&gt;(HttpStatus.&lt;span style=&#34;color:#a6e22e&#34;&gt;UNAUTHORIZED&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; exchange.&lt;span style=&#34;color:#a6e22e&#34;&gt;getResponse&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;setComplete&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Mono&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Void&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;filter&lt;/span&gt;(ServerWebExchange exchange, GatewayFilterChain chain) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ServerHttpRequest request &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; exchange.&lt;span style=&#34;color:#a6e22e&#34;&gt;getRequest&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        String path &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; request.&lt;span style=&#34;color:#a6e22e&#34;&gt;getPath&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;toString&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (isWhiteList(path)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; chain.&lt;span style=&#34;color:#a6e22e&#34;&gt;filter&lt;/span&gt;(exchange);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        String token &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; request.&lt;span style=&#34;color:#a6e22e&#34;&gt;getHeaders&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;getFirst&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Authorization&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 令牌为空，拒绝访问&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;( token &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; token.&lt;span style=&#34;color:#a6e22e&#34;&gt;isEmpty&lt;/span&gt;() ){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; reject( exchange );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 验证令牌&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Integer userId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; jwtUtil.&lt;span style=&#34;color:#a6e22e&#34;&gt;parseToken&lt;/span&gt;(token);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// TODO userId 塞入请求头&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            log.&lt;span style=&#34;color:#a6e22e&#34;&gt;info&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;🚪 塞入请求头&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (Exception e) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; reject(exchange);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; chain.&lt;span style=&#34;color:#a6e22e&#34;&gt;filter&lt;/span&gt;( exchange );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 过滤器优先级，越小越靠前&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getOrder&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>PostgreSQL和java的LocalDateTime不兼容的问题</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/bugs-solutions/postgresql-java-localdatetime-incompatibility/</link>
      <pubDate>Sat, 25 Oct 2025 12:55:49 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/bugs-solutions/postgresql-java-localdatetime-incompatibility/</guid>
      <description>&lt;p&gt;&lt;strong&gt;Java 的 &lt;code&gt;LocalDateTime&lt;/code&gt; 和 PostgreSQL 的时间类型，&amp;ldquo;说的不是同一种时间&amp;rdquo;。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;先搞清楚-postgresql-的两种时间类型&#34;&gt;先搞清楚 PostgreSQL 的两种时间类型&lt;/h2&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;TIMESTAMP           → 不带时区，就是个裸时间 &amp;#34;2026-06-25 10:00:00&amp;#34;
TIMESTAMPTZ         → 带时区，内部存 UTC，查询时按会话时区转换
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id=&#34;java-这边&#34;&gt;Java 这边&lt;/h2&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;LocalDateTime       → 没有时区概念，就是个裸时间
ZonedDateTime       → 带时区
OffsetDateTime      → 带偏移量（如 +08:00）
Instant             → UTC 时间戳
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id=&#34;为什么会报错&#34;&gt;为什么会报错&lt;/h2&gt;
&lt;p&gt;PostgreSQL JDBC 驱动（特别是新版本 42.x+）对类型匹配&lt;strong&gt;非常严格&lt;/strong&gt;：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;flowchart TD
    A[Java LocalDateTime] --&amp;gt; B[JDBC驱动]
    B --&amp;gt; C{PostgreSQL列类型}
    C --&amp;gt;|TIMESTAMP| D[✅ 可以匹配]
    C --&amp;gt;|TIMESTAMPTZ| E[❌ 类型不匹配报错]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;你的列如果是 &lt;code&gt;TIMESTAMPTZ&lt;/code&gt;（带时区），但 Java 传的是 &lt;code&gt;LocalDateTime&lt;/code&gt;（无时区），驱动不知道该用哪个时区换算，就直接拒绝了。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;常见的三种报错&#34;&gt;常见的三种报错&lt;/h2&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Cannot convert LocalDateTime to TIMESTAMPTZ
Bad value for type timestamp/date
column is of type timestamp with time zone but expression is of type timestamp
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id=&#34;解决方案&#34;&gt;解决方案&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;方案一：改 Java 类型（推荐）&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Swagger2和Swagger3注解对比表</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/bugs-solutions/swagger-2-3-annotation-comparison/</link>
      <pubDate>Thu, 25 Sep 2025 09:06:35 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/bugs-solutions/swagger-2-3-annotation-comparison/</guid>
      <description>&lt;p&gt;在 Spring Boot 生态中，Swagger 2.0（通常使用 &lt;code&gt;Foxfire&lt;/code&gt; 依赖）和 Swagger 3.0（通常使用 &lt;code&gt;Springdoc-openapi&lt;/code&gt; 依赖，基于 OpenAPI 3 规范）的注解发生了很大变化。&lt;/p&gt;
&lt;p&gt;以下是 Swagger 2.0 与 Swagger 3.0（OpenAPI 3）的常用注释完整对应表：&lt;/p&gt;
&lt;h3 id=&#34;1-核心注解对应表&#34;&gt;1. 核心注解对应表&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;功能描述&lt;/th&gt;
					&lt;th&gt;Swagger 2.0 注解 (io.swagger.annotations)&lt;/th&gt;
					&lt;th&gt;Swagger 3.0 注解 (io.swagger.v3.oas.annotations)&lt;/th&gt;
					&lt;th&gt;备注说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;标记控制器类&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;@Api(tags = &amp;quot;用户接口&amp;quot;)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;@Tag(name = &amp;quot;用户接口&amp;quot;)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;3.0 中移除了 &lt;code&gt;description&lt;/code&gt; 属性，统一使用 &lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;标记接口方法&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;@ApiOperation(value = &amp;quot;获取用户&amp;quot;)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;@Operation(summary = &amp;quot;获取用户&amp;quot;)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;3.0 中 &lt;code&gt;value&lt;/code&gt; 变更为 &lt;code&gt;summary&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;入参实体类&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;@ApiModel(value = &amp;quot;用户对象&amp;quot;)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;@Schema(description = &amp;quot;用户对象&amp;quot;)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;3.0 极大简化，统一使用 &lt;code&gt;@Schema&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;实体类属性&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;@ApiModelProperty(value = &amp;quot;姓名&amp;quot;)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;@Schema(description = &amp;quot;姓名&amp;quot;)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;同上，合并为了 &lt;code&gt;@Schema&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;忽略某个属性&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;@ApiModelProperty(hidden = true)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;@Schema(hidden = true)&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;忽略整个类/方法&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;@ApiIgnore&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;@Hidden&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;用于不想暴露在文档中的接口或参数&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&#34;2-请求参数注解对应表&#34;&gt;2. 请求参数注解对应表&lt;/h3&gt;
&lt;p&gt;对于方法入参（如 URL 路径参数、Query 参数等），3.0 引入了更具结构化的配置：&lt;/p&gt;</description>
    </item>
    <item>
      <title>程序员快速参考小手册</title>
      <link>https://lv-blog.pages.dev/posts/programming/%E7%A8%8B%E5%BA%8F%E5%91%98%E5%BF%AB%E9%80%9F%E5%8F%82%E8%80%83%E5%B0%8F%E6%89%8B%E5%86%8C/</link>
      <pubDate>Sun, 24 Aug 2025 22:51:14 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/%E7%A8%8B%E5%BA%8F%E5%91%98%E5%BF%AB%E9%80%9F%E5%8F%82%E8%80%83%E5%B0%8F%E6%89%8B%E5%86%8C/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;有的命令一个月可能就用那么几次，不写手册里谁能记得住啊&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;vscode&#34;&gt;VSCode&lt;/h2&gt;
&lt;h3 id=&#34;解决-code-runner-java-output-乱码&#34;&gt;解决 code-runner Java Output 乱码&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;code-runner.executorMap&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;javascript&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;node&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;java&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\&amp;#34;C:/Program Files/Java/jdk-17/bin/java.exe\&amp;#34; -Dfile.encoding=UTF-8&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;powershell&#34;&gt;PowerShell&lt;/h2&gt;
&lt;h3 id=&#34;快速完成端口转发&#34;&gt;快速完成端口转发&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;netsh interface portproxy add v4tov4 &lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;listenaddress&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;0.0.0.0 &lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;listenport&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2375&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;connectaddress&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;127.0.0.1 &lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;connectport&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2375&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;查端口占用-杀进程&#34;&gt;查端口占用 杀进程&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-Shell&#34; data-lang=&#34;Shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;netstat -aon | findstr :8080
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;taskkill /PID &lt;span style=&#34;color:#ae81ff&#34;&gt;39656&lt;/span&gt; /F
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;自定义常用命令别名&#34;&gt;自定义常用命令别名&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;notepad $PROFILE
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; gacp &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    param &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;string&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;$msg &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;update&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    git add .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    git commit -m $msg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    git push
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#  删除当前文件夹下空文件夹&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; rme &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Get-ChildItem -Directory -Recurse | Where-Object &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; $_.GetFileSystemInfos&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt;.Count -eq &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; | Remove-Item
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;linux&#34;&gt;Linux&lt;/h2&gt;
&lt;h3 id=&#34;linux开辟虚拟内存swap&#34;&gt;Linux开辟虚拟内存（Swap）&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;free -h
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;linux实现frp内网穿透&#34;&gt;Linux实现FRP内网穿透&lt;/h3&gt;
&lt;p&gt;的是让国内用户能连到一台&lt;strong&gt;没有公网 IP 的家庭电脑&lt;/strong&gt;——用的是&lt;strong&gt;反向内网穿透&lt;/strong&gt;:&lt;/p&gt;</description>
    </item>
    <item>
      <title>SCA 2023.X — Nacos Bootstrap 配置失效问题排查与解决方案</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/bugs-solutions/sca-nacos-bootstrap-bug/</link>
      <pubDate>Thu, 24 Jul 2025 22:40:26 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/bugs-solutions/sca-nacos-bootstrap-bug/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Issue 来源&lt;/strong&gt;：&lt;a href=&#34;https://github.com/alibaba/spring-cloud-alibaba/issues/3931&#34;&gt;spring-cloud-alibaba#3931&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;影响版本&lt;/strong&gt;：&lt;code&gt;spring-cloud-alibaba 2023.0.1.3+&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一问题描述&#34;&gt;一、问题描述&lt;/h2&gt;
&lt;p&gt;在 Spring Cloud Alibaba 2023.X 版本中，将 Nacos 配置（包括 &lt;code&gt;extension-configs&lt;/code&gt;、&lt;code&gt;shared-configs&lt;/code&gt; 等）放在 &lt;code&gt;bootstrap.yml&lt;/code&gt; / &lt;code&gt;bootstrap.properties&lt;/code&gt; 中，&lt;strong&gt;配置中心的内容无法正常加载&lt;/strong&gt;，但日志显示 &lt;code&gt;bootstrap&lt;/code&gt; 文件本身已被读取。&lt;/p&gt;
&lt;p&gt;将相同配置移到 &lt;code&gt;application.yml&lt;/code&gt; 后，一切恢复正常。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二根本原因&#34;&gt;二、根本原因&lt;/h2&gt;
&lt;pre class=&#34;mermaid&#34;&gt;flowchart TD
    A[bootstrap.yml 被读取] --&gt; B{SCA 版本判断}
    B -- 2023.0.1.2 及以前 --&gt; C[✅ 正常加载 Nacos 配置中心]
    B -- 2023.0.1.3 及以后 --&gt; D[❌ extension-configs / shared-configs 失效]
    D --&gt; E[问题根源：SCA 2023.0.1.3 修改了配置加载优先级机制]
    E --&gt; F[bootstrap 阶段注册的 Nacos PropertySource 被后续流程覆盖或丢弃]
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;简单来说：&lt;/strong&gt;&lt;br&gt;
SCA &lt;code&gt;2023.0.1.3&lt;/code&gt; 做了一次&lt;strong&gt;不向后兼容的内部变更&lt;/strong&gt;，导致 &lt;code&gt;bootstrap.yml&lt;/code&gt; 中的 Nacos 扩展配置在加载链路中被&amp;quot;丢掉&amp;quot;，而 &lt;code&gt;application.yml&lt;/code&gt; 中的配置走的是新路径，不受影响。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Nacos 一些常用配置</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/code-snippets/nacos-config-tips/</link>
      <pubDate>Tue, 24 Jun 2025 19:01:02 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/code-snippets/nacos-config-tips/</guid>
      <description>&lt;h1 id=&#34;bootstrap-配置&#34;&gt;bootstrap 配置&lt;/h1&gt;
&lt;h2 id=&#34;bootstrapyaml&#34;&gt;bootstrap.yaml&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;server&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;10888&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;tomcat&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;uri-encoding&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;UTF-8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spring&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;profiles&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;active&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;dev&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;application&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;archive-service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;cloud&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;nacos&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;config&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;file-extension&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;yaml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;shared-configs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;data-id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;shared-spring.yaml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;refresh&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;data-id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;shared-redis.yaml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;refresh&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;data-id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;shared-mybatis.yaml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;refresh&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;data-id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;shared-logs.yaml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;refresh&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;data-id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;shared-feign.yaml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;refresh&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          - &lt;span style=&#34;color:#f92672&#34;&gt;data-id&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;shared-logs.yaml&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# 共享日志配置&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;refresh&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#          - data-id: shared-feign.yaml # 共享feign配置&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#            refresh: false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;lia&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;jdbc&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;database&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;tb_archive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;bootstrap-devyaml&#34;&gt;bootstrap-dev.yaml&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spring&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;cloud&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;nacos&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;server-addr&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;192.168.2.115&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;8848&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# nacos注册中心&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;discovery&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;namespace&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;f923fb34-cb0a-4c06-8fca-ad61ea61a3f0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;group&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;DEFAULT_GROUP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;ip&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;192.168.2.115&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;logging&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;level&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;asia.liminality&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;debug&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;nacos-配置&#34;&gt;nacos 配置&lt;/h1&gt;
&lt;h2 id=&#34;shared-springyaml&#34;&gt;shared-spring.yaml&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spring&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;jackson&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;default-property-inclusion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;non_null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;main&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;allow-bean-definition-overriding&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;mvc&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;pathmatch&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;#解决异常：swagger Failed to start bean &amp;#39;documentationPluginsBootstrapper&amp;#39;; nested exception is java.lang.NullPointerException&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;#因为Springfox使用的路径匹配是基于AntPathMatcher的，而Spring Boot 2.6.X使用的是PathPatternMatcher&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;matching-strategy&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ant_path_matcher&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;shared-redisyaml&#34;&gt;shared-redis.yaml&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spring&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;redis&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${lia.redis.host:192.168.2.115}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;password&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${lia.redis.password:github}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;lettuce&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;pool&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;max-active&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${lia.redis.pool.max-active:8}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;max-idle&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${lia.redis.pool.max-idle:8}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;min-idle&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${lia.redis.pool.min-idle:1}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;max-wait&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${lia.redis.pool.max-wait:300}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;shared-mybatisyaml&#34;&gt;shared-mybatis.yaml&lt;/h2&gt;
&lt;h3 id=&#34;mysql&#34;&gt;mySQL&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spring&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;datasource&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;driver-class-name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;com.mysql.cj.jdbc.Driver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;url&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;jdbc:mysql://${sh.jdbc.host:127.0.0.1}/${sh.jdbc.database}?useUnicode=true&amp;amp;characterEncoding=utf8&amp;amp;serverTimezone=Asia/Shanghai&amp;amp;useSSL=false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;username&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${lia.jdbc.username:root}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;password&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${lia.jdbc.password:794211}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;mybatis-plus&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;configuration&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;default-enum-type-handler&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;global-config&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;db-config&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;logic-delete-field&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;deletedAt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;logic-not-delete-value&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;null&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;logic-delete-value&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;now()&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;id-type&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;assign_id&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;insert-strategy&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;not_null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;update-strategy&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;not_null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;porstgresql&#34;&gt;porstgreSQL&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spring&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;datasource&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;driver-class-name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;org.postgresql.Driver&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;url&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;jdbc:postgresql://${lia.jdbc.host:192.168.2.115}:${lia.jdbc.port:5432}/${lia.jdbc.database}?useUnicode=true&amp;amp;characterEncoding=UTF-8&amp;amp;autoReconnect=true&amp;amp;serverTimezone=Asia/Shanghai&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;username&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${lia.jdbc.username:postgres}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;password&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${lia.jdbc.password:github}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;mybatis-plus&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;configuration&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;default-enum-type-handler&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;global-config&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;db-config&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;logic-delete-field&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;deletedAt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;logic-not-delete-value&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;null&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;logic-delete-value&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;now()&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;id-type&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;assign_id&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;insert-strategy&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ignored&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;update-strategy&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ignored&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;select-strategy&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;not_null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;shared-logsyaml&#34;&gt;shared-logs.yaml&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;logging&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;pattern&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;dateformat&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;HH:mm:ss.SSS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;console&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%clr(%d{${LOG_DATEFORMAT_PATTERN}}){faint}-[${hostname}][%X{requestId:-sys}] %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;file&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%d{${LOG_DATEFORMAT_PATTERN}}-[${hostname}][%X{requestId:-sys}]-${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%15.15t] %-40.40logger{39} : %m%n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;file&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;path&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;logs/${spring.application.name}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;shared-feignyaml&#34;&gt;shared-feign.yaml&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;feign&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;client&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;config&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;default&lt;/span&gt;: &lt;span style=&#34;color:#75715e&#34;&gt;# default全局的配置&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;loggerLevel&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;BASIC&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# 日志级别，BASIC就是基本的请求和响应信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;httpclient&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;enabled&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# 开启feign对HttpClient的支持&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;max-connections&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# 最大的连接数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;max-connections-per-route&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;50&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# 每个路径的最大连接数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;sentinel&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;enabled&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>微信小程序开发受苦指南</title>
      <link>https://lv-blog.pages.dev/posts/programming/wechatapp-development-notes/</link>
      <pubDate>Wed, 23 Apr 2025 14:02:30 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/wechatapp-development-notes/</guid>
      <description>&lt;h2 id=&#34;微信小程序和后端用户认证交互流程&#34;&gt;微信小程序和后端用户认证交互流程&lt;/h2&gt;
&lt;p&gt;微信小程序登录的核心流程：小程序拿临时凭证 &lt;code&gt;code&lt;/code&gt; → 后端用 &lt;code&gt;code&lt;/code&gt; 换 &lt;code&gt;openid&lt;/code&gt; → 后端发自己的 JWT 给小程序。下面是整体流程图。&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;sequenceDiagram
    participant MP as 微信小程序
    participant WX as 微信服务器
    participant GW as gateway
    participant Auth as auth模块
    participant User as user-service
    participant DB as lia_user库

    MP-&gt;&gt;WX: wx.login() 获取 code
    WX--&gt;&gt;MP: 返回临时 code
    MP-&gt;&gt;GW: POST /auth/wx-login {code}
    GW-&gt;&gt;Auth: 转发请求
    Auth-&gt;&gt;WX: code2session(code)
    WX--&gt;&gt;Auth: 返回 openid + session_key
    Auth-&gt;&gt;User: OpenFeign 查/建用户
    User-&gt;&gt;DB: 按 openid 查询
    DB--&gt;&gt;User: 用户记录(或空)
    User--&gt;&gt;Auth: 返回 userId
    Auth-&gt;&gt;Auth: 生成 JWT
    Auth--&gt;&gt;MP: 返回 token + 用户信息
    MP-&gt;&gt;MP: 存入 Storage
&lt;/pre&gt;
&lt;h3 id=&#34;关键点拆解&#34;&gt;关键点拆解&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. 小程序端拿 code（前端）&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>消息中间件 面试题整理</title>
      <link>https://lv-blog.pages.dev/posts/programming/for-interview/mq-interview-questions/</link>
      <pubDate>Sun, 23 Mar 2025 13:21:54 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/for-interview/mq-interview-questions/</guid>
      <description>&lt;h1 id=&#34;消息队列通识&#34;&gt;消息队列通识&lt;/h1&gt;
&lt;h2 id=&#34;为什么需要消息队列&#34;&gt;为什么需要消息队列&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;解耦&lt;/li&gt;
&lt;li&gt;削峰填谷&lt;/li&gt;
&lt;li&gt;异步调用&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;消息队列如何保持幂等&#34;&gt;消息队列如何保持幂等&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;重复源泉
&lt;ul&gt;
&lt;li&gt;生产端重发
&lt;ul&gt;
&lt;li&gt;发送ACK没有回复继续发送&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;消费端重复&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;解决方案
&lt;ul&gt;
&lt;li&gt;唯一消息ID，生产者发送时携带messageId&lt;/li&gt;
&lt;li&gt;幂等表&lt;/li&gt;
&lt;li&gt;状态机校验&lt;/li&gt;
&lt;li&gt;乐观锁 / 版本号&lt;/li&gt;
&lt;li&gt;分布式锁&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;核心原则
&lt;ul&gt;
&lt;li&gt;消费逻辑天然幂等&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;为什么需要消息队列-1&#34;&gt;为什么需要消息队列&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;解耦&lt;/li&gt;
&lt;li&gt;异步&lt;/li&gt;
&lt;li&gt;削峰&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;消息队列的模型有哪些&#34;&gt;消息队列的模型有哪些&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;点对点模型&lt;/li&gt;
&lt;li&gt;发布订阅模型&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;如何保证消息不丢失&#34;&gt;如何保证消息不丢失&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;生产端
&lt;ul&gt;
&lt;li&gt;ack&lt;/li&gt;
&lt;li&gt;broker 持久化
&lt;ul&gt;
&lt;li&gt;生产环境副本因子 &amp;gt;= 3&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;消费端
&lt;ul&gt;
&lt;li&gt;手动提交 offset&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;如何保证消息有序&#34;&gt;如何保证消息有序&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;让需要保持有序的消息落到同一个分区&lt;/li&gt;
&lt;li&gt;给唯一的key，且key以后不会重复&lt;/li&gt;
&lt;li&gt;Kafka保证唯一分区内有序，跨分区无序&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;rabbitmq&#34;&gt;RabbitMQ&lt;/h1&gt;
&lt;h2 id=&#34;rabbitmq-如何保证消息不丢失&#34;&gt;RabbitMQ 如何保证消息不丢失&lt;/h2&gt;
&lt;!-- TODO 复习 --&gt;
&lt;ul&gt;
&lt;li&gt;哪些情况会丢失
&lt;ul&gt;
&lt;li&gt;publisher -&amp;gt; exchange
&lt;ul&gt;
&lt;li&gt;生产者确认机制
&lt;ul&gt;
&lt;li&gt;ack publish-confirm&lt;/li&gt;
&lt;li&gt;nack publish-confirm&lt;/li&gt;
&lt;li&gt;ack publish-return&lt;/li&gt;
&lt;li&gt;消息失败之后如何处理
&lt;ul&gt;
&lt;li&gt;回调方法&lt;/li&gt;
&lt;li&gt;记录日志&lt;/li&gt;
&lt;li&gt;保存到数据库中然后定时重发&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;exchange -&amp;gt; queue
&lt;ul&gt;
&lt;li&gt;消息持久化
&lt;ul&gt;
&lt;li&gt;交换机持久化&lt;/li&gt;
&lt;li&gt;队列持久化&lt;/li&gt;
&lt;li&gt;消息持久化&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;queue&lt;/li&gt;
&lt;li&gt;queue -&amp;gt; consumer
&lt;ul&gt;
&lt;li&gt;消费者确认机制&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;rabbitmq-消息的重复消费问题是如何解决的&#34;&gt;RabbitMQ 消息的重复消费问题是如何解决的&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;重复消费的原因&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Spring Cloud 面试题整理</title>
      <link>https://lv-blog.pages.dev/posts/programming/for-interview/spring-cloud-interview-questions/</link>
      <pubDate>Sun, 23 Feb 2025 13:20:18 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/for-interview/spring-cloud-interview-questions/</guid>
      <description>&lt;h1 id=&#34;springcloud-问题&#34;&gt;SpringCloud 问题&lt;/h1&gt;
&lt;h2 id=&#34;springcloud-五大组件&#34;&gt;springcloud 五大组件&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Eureka / nacos&lt;/li&gt;
&lt;li&gt;Ribbon&lt;/li&gt;
&lt;li&gt;Feign / dubbo&lt;/li&gt;
&lt;li&gt;Hystrix / sentinel&lt;/li&gt;
&lt;li&gt;Zuul/Gateway&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;服务注册和发现是什么意思springcloud-如何实现服务注册和发现&#34;&gt;服务注册和发现是什么意思，SpringCloud 如何实现服务注册和发现？&lt;/h2&gt;
&lt;h2 id=&#34;nacos-和-eureka-的区别&#34;&gt;nacos 和 eureka 的区别？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;相同点
&lt;ul&gt;
&lt;li&gt;服务提供者 注册 服务信息 到 注册中心&lt;/li&gt;
&lt;li&gt;服务消费者 定时从 注册中心 拉取&lt;/li&gt;
&lt;li&gt;服务消费者 对 服务提供者 进行远程调用&lt;/li&gt;
&lt;li&gt;服务提供者 临时实例 采用心跳检查
&lt;ul&gt;
&lt;li&gt;什么是临时实例？
&lt;ul&gt;
&lt;li&gt;默认实例都是临时实例&lt;/li&gt;
&lt;li&gt;临时实例心跳模式&lt;/li&gt;
&lt;li&gt;非临时主动探测&lt;/li&gt;
&lt;li&gt;临时实例没有心跳会被剔除&lt;/li&gt;
&lt;li&gt;非临时不会被剔除&lt;/li&gt;
&lt;li&gt;ephemeral: false 变成非临时实例
&lt;ul&gt;
&lt;li&gt;非临时实例，nacos会主动询问服务提供者是否存活&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;不同点
&lt;ul&gt;
&lt;li&gt;非临时实例&lt;/li&gt;
&lt;li&gt;nacos集群AP，如果存在非临时实例，采用CP&lt;/li&gt;
&lt;li&gt;eureka采用AP&lt;/li&gt;
&lt;li&gt;nacos还有配置中心&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;你们项目中负载均衡是如何实现的&#34;&gt;你们项目中负载均衡是如何实现的？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Ribbon&lt;/li&gt;
&lt;li&gt;Ribbon 负载均衡流程
&lt;ol&gt;
&lt;li&gt;微服务发起请求&lt;/li&gt;
&lt;li&gt;Ribbon 从注册中心拉取&lt;/li&gt;
&lt;li&gt;根据策略进行转发&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;ribbon-负载均衡策略有哪些&#34;&gt;Ribbon 负载均衡策略有哪些？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RoundRobinRule&lt;/strong&gt; 简单轮询&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WeightedResponseTimeRule&lt;/strong&gt; 按照权重来选择服务器，响应时间越长，权重越小&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RandomRule&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;BestAvailableRule 忽略短路的服务器，选择并发数较低的服务器&lt;/li&gt;
&lt;li&gt;RetryRule 重试机制的选择逻辑（基于轮询）&lt;/li&gt;
&lt;li&gt;AvailabilityFilteringRule 可用性敏感策略。先过滤非健康的，再选择连接数比较小的&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ZoneAvoidanceRule&lt;/strong&gt; 以区域可用的服务器为基础对服务器选择。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;如果想自定义负载均衡策略如何实现&#34;&gt;如果想自定义负载均衡策略，如何实现？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;自己创建类实现 IRule 接口， 再通过配置类或配置文件配置&lt;/li&gt;
&lt;li&gt;@Bean IRule 全局生效&lt;/li&gt;
&lt;li&gt;NFLoadBalancerRuleClassName 局部生效&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;什么是服务雪崩如何解决这个问题&#34;&gt;什么是服务雪崩？如何解决这个问题？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;服务雪崩
&lt;ul&gt;
&lt;li&gt;一个服务失败，导致整条链路都失败的情形&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;解决方案
&lt;ul&gt;
&lt;li&gt;降级（接口）
&lt;ul&gt;
&lt;li&gt;Feign 接口走fallback&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;熔断（整个服务）
&lt;ul&gt;
&lt;li&gt;Hystix
&lt;ul&gt;
&lt;li&gt;@EnableCircuitBreaker&lt;/li&gt;
&lt;li&gt;断路器关闭 - 打开 - 半开&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;你们的微服务是怎么监控的&#34;&gt;你们的微服务是怎么监控的？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;skywalking
&lt;ul&gt;
&lt;li&gt;apache顶级项目&lt;/li&gt;
&lt;li&gt;问题定位&lt;/li&gt;
&lt;li&gt;性能分析&lt;/li&gt;
&lt;li&gt;服务关系&lt;/li&gt;
&lt;li&gt;服务告警&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;业务相关&#34;&gt;业务相关&lt;/h1&gt;
&lt;h2 id=&#34;项目中有没有做过限流怎么做的&#34;&gt;项目中有没有做过限流？怎么做的？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;限流情况&lt;/p&gt;</description>
    </item>
    <item>
      <title>Java 面试题整理</title>
      <link>https://lv-blog.pages.dev/posts/programming/for-interview/java-interview-questions/</link>
      <pubDate>Thu, 23 Jan 2025 08:50:54 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/for-interview/java-interview-questions/</guid>
      <description>&lt;h1 id=&#34;集合&#34;&gt;集合&lt;/h1&gt;
&lt;h2 id=&#34;为什么数组索引要从-0-开始从-1-开始不行吗&#34;&gt;为什么数组索引要从 0 开始？从 1 开始不行吗？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;回答大纲&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数组在内存中是连续存储的，CPU 通过寻址公式访问元素&lt;/li&gt;
&lt;li&gt;从 0 开始：&lt;code&gt;a[i]_address = base_address + i * typeSize&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;从 1 开始：&lt;code&gt;base_address + (i-1) * typeSize&lt;/code&gt;，多一次减法&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;正式回答&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;数组在内存中是连续存储的，CPU 通过寻址公式来访问指定下标的元素：&lt;code&gt;a[i] 的地址 = 数组首地址 + i * 元素大小&lt;/code&gt;。当数组下标从 0 开始时，直接套用上述公式即可计算偏移量；如果下标从 1 开始，则需要先执行 &lt;code&gt;i - 1&lt;/code&gt; 再做乘法，多了一次减法运算。虽然单次访问的差异可以忽略不计，但数组通常会出现在循环、遍历等高频访问的场景中，这笔额外开销会被无限放大。这也是 C 语言沿用下来的历史约定，Java 作为一门追求高效的系统级语言，继承了这一设计。&lt;/p&gt;
&lt;h2 id=&#34;时间复杂度如何计算的&#34;&gt;时间复杂度如何计算的？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;回答大纲&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;口诀：常 对 幂 指 阶&lt;/li&gt;
&lt;li&gt;常见复杂度
&lt;ul&gt;
&lt;li&gt;常数复杂度 O(1)：不随 n 变化&lt;/li&gt;
&lt;li&gt;对数复杂度 O(logN)：二分查找、树操作&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;正式回答&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;时间复杂度用于衡量算法执行时间随数据规模 n 增长的变化趋势，是大 O 表示法下对最坏情况的抽象描述。常见的大小关系可用口诀&amp;quot;常对幂指阶&amp;quot;来记忆，即 O(1) &amp;lt; O(logN) &amp;lt; O(N) &amp;lt; O(N*logN) &amp;lt; O(N²) &amp;lt; O(2ⁿ) &amp;lt; O(n!)，越靠后算法越慢。&lt;/p&gt;</description>
    </item>
    <item>
      <title>为什么国内大厂全面撤掉了公共 Docker 镜像源？</title>
      <link>https://lv-blog.pages.dev/posts/programming/why-why-why/why-rare-docker-images/</link>
      <pubDate>Mon, 23 Dec 2024 08:16:01 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/why-why-why/why-rare-docker-images/</guid>
      <description>&lt;p&gt;2024 到 2025 年这两年，阿里云、腾讯云、网易、科大讯飞，还有各大高校的公共 Docker 镜像站，基本上是一波接一波地关的关、限的限。到了 2026 年，&amp;ldquo;拉个镜像如渡劫&amp;quot;这句话已经不是玩笑了。&lt;/p&gt;
&lt;p&gt;很多人第一反应是骂大厂抠门。但说实话，这事没那么简单。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;合规这座山绕不过去&#34;&gt;合规这座山绕不过去&lt;/h3&gt;
&lt;p&gt;Docker Hub 是个全球开放的社区，任何人都能往上面推镜像，没有人在入口做内容审查。这就意味着里面什么都有——有漏洞的镜像、带恶意软件的镜像，乃至触碰国内监管红线的内容，全都混在里面。&lt;/p&gt;
&lt;p&gt;问题在于，只要阿里云的服务器把这些东西同步下来，再转发给用户，阿里云就天然地成了&amp;quot;中间人&amp;rdquo;。在现行的监管逻辑下，平台不能说&amp;quot;我只是个镜子，内容不是我的&amp;quot;——你提供了传播通道，你就得负责。这种连带风险，没有哪家大厂愿意为一个免费服务去扛。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;带宽这笔账算不过来&#34;&gt;带宽这笔账算不过来&lt;/h3&gt;
&lt;p&gt;Docker 镜像这个东西和 npm、pip 那些包依赖有本质的不同——它就是重。一个普通的 Node.js 基础镜像几百 MB 起步，稍微带点 CUDA 或者 PyTorch 环境的，动辄就是好几个 GB。&lt;/p&gt;
&lt;p&gt;国内用镜像源的群体又特别杂：开发者、CI/CD 流水线、还有成千上万台家用 NAS——群晖、极空间这些，很多人设置成定时自动更新，24 小时都在跑。这些流量全是公网出口流量，大厂一分钱都收不到，还得自己掏带宽的钱。&lt;/p&gt;
&lt;p&gt;原本这种事情算是一种社区口碑投资，但现在各家都在降本增效，这种&amp;quot;纯出血、零转化&amp;quot;的项目，砍起来是毫不手软的。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;大厂没有放弃加速只是换了玩法&#34;&gt;大厂没有放弃加速，只是换了玩法&lt;/h3&gt;
&lt;p&gt;阿里云和腾讯云并没有把镜像加速这个能力整个下线，而是把它圈起来了。&lt;/p&gt;
&lt;p&gt;现在的逻辑大概是这样的：你如果买了他们的 ECS，在内网环境里拉镜像，依然是快的、免费的。你如果想在公网用，那你得注册账号、开通 ACR（容器镜像服务），生成一个绑定了你身份的专属加速地址。一旦你的账号有异常，随时可以溯源和封禁。&lt;/p&gt;
&lt;p&gt;换句话说，大厂的态度变成了：你是我的付费用户，或者至少是实名用户，我可以给你开小灶；你要是想匿名白嫖，那就没有这个服务了。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;那现在大家怎么办&#34;&gt;那现在大家怎么办？&lt;/h3&gt;
&lt;p&gt;目前社区里摸索出来的路子主要有几条。&lt;/p&gt;
&lt;p&gt;一种是去找垂直的合规镜像站，比如开放原子基金会的 AtomHub，但它只收录了三百多个经过安全审计的基础镜像，能找到自己想要的东西的概率不高。还有一些商业和公益混合性质的服务，比如轩辕镜像、毫秒镜像，口碑还行，但也说不准能撑多久。&lt;/p&gt;
&lt;p&gt;另一种是去开通阿里云或腾讯云的个人 ACR，拿到专属链接，老老实实实名用。&lt;/p&gt;
&lt;p&gt;最彻底的做法，是自己在香港或者新加坡搞一台便宜的 VPS，用 Nginx 或者 Cloudflare Workers 自建一个反向代理，专供自己用，不对外开放。速度有保障，也不怕被人蹭流量拖垮。很多企业内部和有折腾精神的开发者，现在基本都走这条路了。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Cloudflare 业务学习</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/cloudflare/</link>
      <pubDate>Sat, 23 Nov 2024 00:37:30 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/cloudflare/</guid>
      <description></description>
    </item>
    <item>
      <title>Spring 面试题整理</title>
      <link>https://lv-blog.pages.dev/posts/programming/for-interview/spring-interview-questions/</link>
      <pubDate>Sat, 19 Oct 2024 23:19:24 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/for-interview/spring-interview-questions/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;面试题从互联网各个角落收集而来&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;谈一谈-spring-ioc-的底层实现&#34;&gt;谈一谈 Spring IOC 的底层实现？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;反射&lt;/li&gt;
&lt;li&gt;工厂的价值&lt;/li&gt;
&lt;li&gt;设计模式&lt;/li&gt;
&lt;li&gt;关键的几个方法
&lt;ul&gt;
&lt;li&gt;createBeanFactory&lt;/li&gt;
&lt;li&gt;getBean&lt;/li&gt;
&lt;li&gt;doGetBean&lt;/li&gt;
&lt;li&gt;createBean&lt;/li&gt;
&lt;li&gt;doCreateBean&lt;/li&gt;
&lt;li&gt;createBeanInstance(getDeclaredConstructor, newInstance)「方案选单」&lt;/li&gt;
&lt;li&gt;populateBean&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&#34;mermaid&#34;&gt;flowchart TD
    A[开始] --&gt; B[&#34;createBeanFactory()&lt;br/&gt;创建 DefaultListableBeanFactory&#34;]
    B --&gt; C[加载 BeanDefinition&lt;br/&gt;解析 XML/注解]
    C --&gt; D[&#34;getBean(beanName)&lt;br/&gt;外部调用入口&#34;]

    D --&gt; E[&#34;doGetBean(beanName)&#34;]
    E --&gt; F{从缓存获取单例?}
    F --&gt;|是| G[返回缓存的 Bean]
    F --&gt;|否| H[&#34;createBean(beanName, mbd)&#34;]

    H --&gt; I[&#34;doCreateBean(beanName, mbd)&#34;]
    I --&gt; J[&#34;createBeanInstance()&lt;br/&gt;getDeclaredConstructor + newInstance&#34;]
    J --&gt; K[&#34;populateBean()&lt;br/&gt;属性填充/依赖注入&#34;]
    K --&gt; L[&#34;initializeBean()&lt;br/&gt;初始化回调&#34;]
    L --&gt; M[注册销毁方法]
    M --&gt; N[返回完整 Bean 实例]
&lt;/pre&gt;
&lt;h2 id=&#34;谈谈-springioc-的理解原理和实现&#34;&gt;谈谈 SpringIOC 的理解，原理和实现？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;IOC 思想&lt;/li&gt;
&lt;li&gt;DI 实现手段&lt;/li&gt;
&lt;li&gt;什么是容器 什么是Bean&lt;/li&gt;
&lt;li&gt;BeanDefination
&lt;ul&gt;
&lt;li&gt;从哪里读
&lt;ul&gt;
&lt;li&gt;XML&lt;/li&gt;
&lt;li&gt;注解&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;存哪里
&lt;ul&gt;
&lt;li&gt;所有 BeanDefinition 都存在 DefaultListableBeanFactory 里的一个 Map 中&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;容器的生命周期&#34;&gt;容器的生命周期&lt;/h2&gt;
&lt;pre class=&#34;mermaid&#34;&gt;flowchart TD
    START([🚀 程序启动]) --&gt; REFRESH[&#34;AbstractApplicationContext.refresh()&#34;]

    REFRESH --&gt; PHASE1

    subgraph PHASE1[&#34;🔵 第一阶段：准备工作&#34;]
        direction TB
        A1[&#34;prepareRefresh()\n记录启动时间\n设置容器状态为「活跃」\n初始化环境变量&#34;] --&gt; A2
        A2[&#34;obtainFreshBeanFactory()\n创建 DefaultListableBeanFactory\n这是容器的核心仓库&#34;] --&gt; A3
        A3[&#34;prepareBeanFactory()\n注册基础 BeanPostProcessor\n注册 Aware 相关处理器\n注册默认环境 Bean（environment）&#34;]
    end

    PHASE1 --&gt; PHASE2

    subgraph PHASE2[&#34;🟢 第二阶段：加载 BeanDefinition（读图纸）&#34;]
        direction TB
        B1[&#34;扫描 @ComponentScan 指定的包\n或读取 XML 配置文件&#34;] --&gt; B2
        B2[&#34;解析注解 / XML\n识别 @Component @Service\n@Repository @Controller @Bean&#34;] --&gt; B3
        B3[&#34;为每个 Bean 生成 BeanDefinition\n记录：类名、作用域、是否懒加载\n初始化方法、销毁方法、依赖关系&#34;] --&gt; B4
        B4[(&#34;存入 beanDefinitionMap\nkey = beanName\nvalue = BeanDefinition&#34;)]
    end

    PHASE2 --&gt; PHASE3

    subgraph PHASE3[&#34;🟡 第三阶段：修改 BeanDefinition（修图纸）&#34;]
        direction TB
        C1[&#34;invokeBeanFactoryPostProcessors()\n执行所有 BeanFactoryPostProcessor&#34;] --&gt; C2
        C2[&#34;ConfigurationClassPostProcessor\n处理 @Configuration @Import\n@PropertySource @ComponentScan\n👉 SpringBoot 自动装配在此触发&#34;] --&gt; C3
        C3[&#34;PropertySourcesPlaceholderConfigurer\n替换 BeanDefinition 中\n所有 ${xxx} 占位符为真实值&#34;] --&gt; C4
        C4[/&#34;所有 BeanDefinition 最终确定\n图纸不再变动&#34;/]
    end

    PHASE3 --&gt; PHASE4

    subgraph PHASE4[&#34;🌸 第四阶段：注册 BeanPostProcessor（工人就位）&#34;]
        direction TB
        D1[&#34;registerBeanPostProcessors()\n按优先级顺序注册\nPriorityOrdered → Ordered → 普通&#34;] --&gt; D2
        D2[&#34;AutowiredAnnotationBeanPostProcessor\n负责处理 @Autowired @Value&#34;] --&gt; D3
        D3[&#34;CommonAnnotationBeanPostProcessor\n负责处理 @PostConstruct @PreDestroy @Resource&#34;] --&gt; D4
        D4[&#34;AnnotationAwareAspectJAutoProxyCreator\n负责检测切面、生成 AOP 代理对象&#34;] --&gt; D5
        D5[/&#34;所有工人就位\n等待 Bean 创建时介入\n此时不开工&#34;/]
    end

    PHASE4 --&gt; PHASE5

    subgraph PHASE5[&#34;🟣 第五阶段：容器基础设施初始化&#34;]
        direction TB
        E1[&#34;initMessageSource()\n初始化国际化资源 i18n&#34;] --&gt; E2
        E2[&#34;initApplicationEventMulticaster()\n初始化事件广播器&#34;] --&gt; E3
        E3[&#34;onRefresh()\n⭐ SpringBoot 在此启动\nTomcat / Jetty / Undertow\nWeb 容器开始监听端口&#34;] --&gt; E4
        E4[&#34;registerListeners()\n注册所有 ApplicationListener\n监听容器事件&#34;]
    end

    PHASE5 --&gt; PHASE6

    subgraph PHASE6[&#34;🟠 第六阶段：实例化所有单例 Bean&#34;]
        direction TB
        F1[&#34;finishBeanFactoryInitialization()\npreInstantiateSingletons()\n遍历所有非懒加载单例 BeanDefinition&#34;] --&gt; F2
        F2[&#34;逐个执行 getBean()\n触发每个 Bean 的生命周期\n实例化 → 属性填充 → Aware回调\n→ 前置处理 → init方法 → 后置处理&#34;] --&gt; F3
        F3[(&#34;所有单例 Bean 存入\nsingletonObjects 一级缓存\n✅ 全部就绪&#34;)]
    end

    PHASE6 --&gt; PHASE7

    subgraph PHASE7[&#34;✅ 第七阶段：容器就绪&#34;]
        direction TB
        G1[&#34;finishRefresh()\n清理启动时占用的资源\n初始化生命周期处理器&#34;] --&gt; G2
        G2[&#34;发布 ContextRefreshedEvent\n通知所有监听者：容器启动完成&#34;] --&gt; G3
        G3[/&#34;容器进入运行状态\n可以处理业务请求&#34;/]
    end

    G3 --&gt; RUNNING([🎉 容器正常运行中])

    RUNNING -.-&gt;|&#34;收到关闭信号\nCtrl+C / kill / close()&#34;| PHASE8

    subgraph PHASE8[&#34;🔴 第八阶段：容器销毁&#34;]
        direction TB
        H1[&#34;发布 ContextClosedEvent\n通知所有监听者：容器即将关闭&#34;] --&gt; H2
        H2[&#34;停止 Web 容器\nTomcat 停止接受新请求&#34;] --&gt; H3
        H3[&#34;执行所有 Bean 的销毁逻辑\n@PreDestroy → destroy() → destroy-method\n按注册顺序逆序销毁&#34;] --&gt; H4
        H4[&#34;清空所有缓存\nsingletonObjects 清空\nbeanDefinitionMap 清空&#34;] --&gt; H5
        H5[&#34;容器状态设置为「关闭」\nactive = false / closed = true&#34;]
    end

    H5 --&gt; END([💀 容器销毁完成])

    style START fill:#43A047,color:#fff
    style RUNNING fill:#43A047,color:#fff
    style END fill:#e53935,color:#fff
    style REFRESH fill:#1E88E5,color:#fff
&lt;/pre&gt;
&lt;h2 id=&#34;bean-的生命周期&#34;&gt;bean 的生命周期&lt;/h2&gt;
&lt;pre class=&#34;mermaid&#34;&gt;flowchart TD
    START([🌱 开始创建 Bean]) --&gt; A

    A[&#34;① 实例化\nInstantiation\n反射调用构造方法\nnew 出空壳对象\n此时所有字段都是 null&#34;] --&gt; B

    B[&#34;② 放入三级缓存\nsingletonFactories\n提前暴露半成品\n为循环依赖做准备&#34;] --&gt; C

    C[&#34;③ 属性填充\npopulateBean()\n处理 @Autowired @Value\n把依赖的 Bean 注入进来&#34;] --&gt; D

    subgraph AWARE[&#34;④ Aware 回调&#34;]
        direction TB
        D[&#34;BeanNameAware\n告诉 Bean 自己叫什么名字&#34;] --&gt; E
        E[&#34;BeanFactoryAware\n把 BeanFactory 塞给 Bean&#34;] --&gt; F
        F[&#34;ApplicationContextAware\n把 ApplicationContext 塞给 Bean&#34;]
    end

    subgraph INIT[&#34;⑤ 初始化 initializeBean()&#34;]
        direction TB
        G[&#34;前置处理\npostProcessBeforeInitialization()\n所有 BeanPostProcessor 挨个执行\n📌 @PostConstruct 在这里被调用&#34;] --&gt; INITMETHOD

        subgraph INITMETHOD[&#34;init 方法（按顺序执行）&#34;]
            direction TB
            H1[&#34;第1个：@PostConstruct\n（已在前置处理中执行）&#34;] --&gt; H2
            H2[&#34;第2个：afterPropertiesSet()\n实现 InitializingBean 接口&#34;] --&gt; H3
            H3[&#34;第3个：init-method\n@Bean(initMethod=&#39;xxx&#39;) 或 XML 配置&#34;]
        end

        INITMETHOD --&gt; I

        I[&#34;后置处理\npostProcessAfterInitialization()\n所有 BeanPostProcessor 挨个执行\n⭐ AOP 代理在这里生成&#34;]
    end

    AWARE --&gt; INIT

    I --&gt; J

    subgraph CACHE[&#34;⑥ 存入缓存&#34;]
        direction TB
        J[&#34;从三级缓存 singletonFactories 移除\n从二级缓存 earlySingletonObjects 移除&#34;] --&gt; K
        K[&#34;存入一级缓存 singletonObjects\n✅ 完整 Bean 就绪&#34;]
    end

    K --&gt; READY([🎉 Bean 可以正常使用了])

    READY -.-&gt;|&#34;容器关闭&#34;| DESTROY

    subgraph DESTROY[&#34;⑦ 销毁阶段（容器关闭时）&#34;]
        direction TB
        D1[&#34;第1个：@PreDestroy\n方法被调用&#34;] --&gt; D2
        D2[&#34;第2个：destroy()\n实现 DisposableBean 接口&#34;] --&gt; D3
        D3[&#34;第3个：destroy-method\n@Bean(destroyMethod=&#39;xxx&#39;) 或 XML 配置&#34;]
    end

    D3 --&gt; END([💀 Bean 销毁完成])
&lt;/pre&gt;
&lt;h2 id=&#34;spring-三级缓存依赖流程&#34;&gt;spring 三级缓存依赖流程&lt;/h2&gt;
&lt;pre class=&#34;mermaid&#34;&gt;sequenceDiagram
    participant Spring as Spring容器
    participant L3 as 三级缓存&lt;br/&gt;singletonFactories
    participant L2 as 二级缓存&lt;br/&gt;earlySingletonObjects
    participant L1 as 一级缓存&lt;br/&gt;singletonObjects

    Note over Spring: 开始创建 A

    Spring-&gt;&gt;Spring: ① new A 空壳对象
    Spring-&gt;&gt;L3: ② 存入 A 的 ObjectFactory lambda

    Note over Spring: 给 A 注入属性，发现需要 B

    Spring-&gt;&gt;Spring: ③ new B 空壳对象
    Spring-&gt;&gt;L3: ④ 存入 B 的 ObjectFactory lambda

    Note over Spring: 给 B 注入属性，发现需要 A

    Spring-&gt;&gt;L1: ⑤ getBean(A)，查一级缓存
    L1--&gt;&gt;Spring: ❌ 没有

    Spring-&gt;&gt;L2: 查二级缓存
    L2--&gt;&gt;Spring: ❌ 没有

    Spring-&gt;&gt;L3: 查三级缓存
    L3--&gt;&gt;Spring: ✅ 找到 A 的 lambda！

    Spring-&gt;&gt;Spring: ⑥ 执行 lambda&lt;br/&gt;（需要代理则生成代理 A）
    Spring-&gt;&gt;L2: ⑦ 早期引用放入二级缓存
    Spring-&gt;&gt;L3: 删除三级缓存中的 A

    Note over Spring: B 拿到 A 的早期引用，B 完成初始化

    Spring-&gt;&gt;L1: ⑧ B 放入一级缓存 ✅
    Spring-&gt;&gt;L3: 删除三级缓存中的 B

    Note over Spring: 回到 A 的流程，B 已就绪，A 完成初始化

    Spring-&gt;&gt;L1: ⑨ A 放入一级缓存 ✅
    Spring-&gt;&gt;L2: 删除二级缓存中的 A

    Note over L1: 最终：一级缓存中有完整的 A 和 B ✅
&lt;/pre&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;情况&lt;/th&gt;
					&lt;th&gt;三级缓存&lt;/th&gt;
					&lt;th&gt;lambda 执行&lt;/th&gt;
					&lt;th&gt;二级缓存&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;无循环依赖，无 AOP&lt;/td&gt;
					&lt;td&gt;存了 lambda&lt;/td&gt;
					&lt;td&gt;❌ 不执行&lt;/td&gt;
					&lt;td&gt;不经过&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;无循环依赖，有 AOP&lt;/td&gt;
					&lt;td&gt;存了 lambda&lt;/td&gt;
					&lt;td&gt;❌ 不执行&lt;/td&gt;
					&lt;td&gt;不经过&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;有循环依赖，无 AOP&lt;/td&gt;
					&lt;td&gt;存了 lambda&lt;/td&gt;
					&lt;td&gt;✅ 执行&lt;/td&gt;
					&lt;td&gt;存原始对象&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;有循环依赖，有 AOP&lt;/td&gt;
					&lt;td&gt;存了 lambda&lt;/td&gt;
					&lt;td&gt;✅ 执行&lt;/td&gt;
					&lt;td&gt;存代理对象&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;spring-bean-缓存的放置时间和删除时间&#34;&gt;spring bean 缓存的放置时间和删除时间&lt;/h2&gt;
&lt;h2 id=&#34;spring-bean-三级缓存的放置与删除时间&#34;&gt;Spring Bean 三级缓存的放置与删除时间&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;缓存&lt;/th&gt;
					&lt;th&gt;存的是什么&lt;/th&gt;
					&lt;th&gt;放入时机&lt;/th&gt;
					&lt;th&gt;删除时机&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;三级 &lt;code&gt;singletonFactories&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Bean 的工厂 lambda&lt;/td&gt;
					&lt;td&gt;实例化完成后立刻放入&lt;/td&gt;
					&lt;td&gt;工厂被调用时（升级到二级）或 Bean 完成时&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;二级 &lt;code&gt;earlySingletonObjects&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;早期暴露的半成品 Bean&lt;/td&gt;
					&lt;td&gt;三级工厂被调用的瞬间&lt;/td&gt;
					&lt;td&gt;Bean 完全初始化完成放入一级时&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;一级 &lt;code&gt;singletonObjects&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;完整可用的 Bean&lt;/td&gt;
					&lt;td&gt;初始化全部完成后&lt;/td&gt;
					&lt;td&gt;容器关闭销毁时&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;beanfactory-和-factorybean-的区别&#34;&gt;BeanFactory 和 FactoryBean 的区别？&lt;/h2&gt;
&lt;h3 id=&#34;factorybean-是什么&#34;&gt;FactoryBean 是什么&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;FactoryBean&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 返回 Bean 的实例（可以是复杂创建逻辑）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    T &lt;span style=&#34;color:#a6e22e&#34;&gt;getObject&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; Exception;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 返回 Bean 的类型&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Class&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&amp;gt;&lt;/span&gt; getObjectType();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 是否单例&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;isSingleton&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;相同点
&lt;ul&gt;
&lt;li&gt;都是用来创建Bean对象的&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;不同点
&lt;ul&gt;
&lt;li&gt;使用 BeanFactory 创建对象的适合必须遵循严格的生命周期流程，太复杂了。如果想简单自定义某个对象的创建，同时想交给spring管理，那么必须实现 FactoryBean 接口
&lt;ul&gt;
&lt;li&gt;isSingleton 是否是单例对象&lt;/li&gt;
&lt;li&gt;getObjectType 获取返回对象的类型&lt;/li&gt;
&lt;li&gt;getObject 自定义创建对象的过程&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;对比维度&lt;/th&gt;
					&lt;th&gt;BeanFactory&lt;/th&gt;
					&lt;th&gt;FactoryBean&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;角色&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;容器/工厂接口&lt;/td&gt;
					&lt;td&gt;特殊的 Bean&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;功能&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;管理所有 Bean 的生命周期&lt;/td&gt;
					&lt;td&gt;自定义某个 Bean 的创建逻辑&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;定位&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;基础设施（IOC 容器）&lt;/td&gt;
					&lt;td&gt;业务扩展（创建复杂对象）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;使用方式&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;由 Spring 框架实现和使用&lt;/td&gt;
					&lt;td&gt;由开发者实现，注册到容器中&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;常见实现&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;DefaultListableBeanFactory&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;SqlSessionFactoryBean&lt;/code&gt;、&lt;code&gt;ProxyFactoryBean&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;谁创建谁&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;BeanFactory&lt;/code&gt; 创建并管理 &lt;code&gt;FactoryBean&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;FactoryBean&lt;/code&gt; 创建业务对象&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;pre class=&#34;mermaid&#34;&gt;flowchart LR
    subgraph BeanFactory[BeanFactory - IOC容器]
        direction LR
        Bean1[普通 Bean]
        Bean2[普通 Bean]
        FB[FactoryBean&lt;br/&gt;特殊 Bean]
    end

    FB --&gt;|调用 getObject| Result[业务对象]

    User[开发者] --&gt;|getBean| BF[BeanFactory]
    BF --&gt;|返回| Bean1
    BF --&gt;|返回| Bean2
    BF --&gt;|返回 getObject 结果| Result
    BF --&gt;|加 &amp; 前缀| FB
&lt;/pre&gt;
&lt;h2 id=&#34;spring中用到的设计模式&#34;&gt;Spring中用到的设计模式&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;单例模式&lt;/li&gt;
&lt;li&gt;原型模式（指定作用域为prototype）&lt;/li&gt;
&lt;li&gt;工厂模式
&lt;ul&gt;
&lt;li&gt;BeanFactory&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;模板方法
&lt;ul&gt;
&lt;li&gt;JdbcTemplate&lt;/li&gt;
&lt;li&gt;TransactionTemplate&lt;/li&gt;
&lt;li&gt;RestTemplate&lt;/li&gt;
&lt;li&gt;RedisTemplate&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;策略模式
&lt;ul&gt;
&lt;li&gt;XmlBeanDefinitionReader&lt;/li&gt;
&lt;li&gt;PropertiesBeanDefinitionReader&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;观察者模式
&lt;ul&gt;
&lt;li&gt;listener&lt;/li&gt;
&lt;li&gt;event&lt;/li&gt;
&lt;li&gt;multicast&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;适配器模式
&lt;ul&gt;
&lt;li&gt;HandlerAdapter&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;装饰者模式
&lt;ul&gt;
&lt;li&gt;BeanWrapper&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;责任链模式
&lt;ul&gt;
&lt;li&gt;使用aop的时候会先生成一个拦截器链&lt;/li&gt;
&lt;li&gt;SpringMVC 的filter责任链&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;代理模式
&lt;ul&gt;
&lt;li&gt;动态代理&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;委托者模式
&lt;ul&gt;
&lt;li&gt;delegate&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;spring-aop-底层实现原理&#34;&gt;Spring AOP 底层实现原理&lt;/h2&gt;
&lt;h3 id=&#34;-第一层一句话定性开场&#34;&gt;🥇 第一层：一句话定性（开场）&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Spring AOP 的底层本质是&lt;strong&gt;动态代理&lt;/strong&gt;。Spring 在容器初始化 Bean 的时候，通过 &lt;code&gt;BeanPostProcessor&lt;/code&gt; 机制拦截，判断这个 Bean 是否需要被增强，如果需要，就用动态代理生成一个代理对象，替换掉原始 Bean 注册进容器。后续所有对这个 Bean 的调用，实际上都是在走代理对象。&amp;rdquo;&lt;/p&gt;</description>
    </item>
    <item>
      <title>MySQL 面试题整理</title>
      <link>https://lv-blog.pages.dev/posts/programming/for-interview/mysql-interview-questions/</link>
      <pubDate>Thu, 19 Sep 2024 23:19:24 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/for-interview/mysql-interview-questions/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;面试题从互联网各个角落收集而来&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;如何定位慢查询&#34;&gt;如何定位慢查询？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;方案1
&lt;ul&gt;
&lt;li&gt;开源工具
&lt;ul&gt;
&lt;li&gt;Arthas&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;运维工具
&lt;ul&gt;
&lt;li&gt;Prometheus&lt;/li&gt;
&lt;li&gt;Skywalking&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;方案2
&lt;ul&gt;
&lt;li&gt;MySQL自带慢日志(mysql性能损耗)
&lt;ul&gt;
&lt;li&gt;开启慢日志方法
&lt;ul&gt;
&lt;li&gt;/etc/my.conf
&lt;ul&gt;
&lt;li&gt;slow_query_log&lt;/li&gt;
&lt;li&gt;long_query_time&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;sql语句执行很慢如何分析&#34;&gt;SQL语句执行很慢，如何分析&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;慢的原因
&lt;ul&gt;
&lt;li&gt;聚合查询&lt;/li&gt;
&lt;li&gt;多表查询&lt;/li&gt;
&lt;li&gt;表数据量过大查询&lt;/li&gt;
&lt;li&gt;深度分页查询&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;如何分析慢
&lt;ul&gt;
&lt;li&gt;explain， desc 命令
&lt;ul&gt;
&lt;li&gt;如何分析执行结果？
&lt;ul&gt;
&lt;li&gt;extra 的额外优化建议
&lt;ul&gt;
&lt;li&gt;using where; using index 查找使用了索引，需要的数据在索引列都能找到，不需要回表查询数据&lt;/li&gt;
&lt;li&gt;using index condition 查找使用了索引&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;type
&lt;ul&gt;
&lt;li&gt;index，all 需要优化&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;了解过索引吗什么是索引&#34;&gt;了解过索引吗？什么是索引？&lt;/h2&gt;
&lt;p&gt;索引（index）是帮助 MySQL 高效获取数据的数据结构（有序）。在数据之外，数据库系统还维护着满足特定查找算法的数据结构（如 B+ 树），这些数据结构以某种方式引用（指向）数据，这样就可以在这些数据结构上实现高级查找算法，这种数据结构就是索引。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;帮助MySQL高效获取数据的数据结构&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;索引的底层数据结构了解过吗&#34;&gt;索引的底层数据结构了解过吗？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;二叉搜索树&lt;/li&gt;
&lt;li&gt;红黑树&lt;/li&gt;
&lt;li&gt;B树&lt;/li&gt;
&lt;li&gt;B+树
&lt;ul&gt;
&lt;li&gt;阶数更多，路径更短&lt;/li&gt;
&lt;li&gt;磁盘读写代价B+树更低，叶子节点才能真正存储数据&lt;/li&gt;
&lt;li&gt;便于扫库和区间查询，叶子节点是双向链表&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;什么是聚簇索引什么是非聚簇索引&#34;&gt;什么是聚簇索引？什么是非聚簇索引？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;聚簇索引&lt;/li&gt;
&lt;li&gt;二级索引&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;什么是回表查询&#34;&gt;什么是回表查询？&lt;/h2&gt;
&lt;h2 id=&#34;知道什么是覆盖索引吗&#34;&gt;知道什么是覆盖索引吗？&lt;/h2&gt;
&lt;p&gt;通过该索引查询能够一次找到所有数据，且无需回表的，就是覆盖索引&lt;/p&gt;
&lt;h2 id=&#34;mysql超大分页怎么处理&#34;&gt;MySQL超大分页怎么处理？&lt;/h2&gt;
&lt;p&gt;使用覆盖索引加上子查询&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-mysql&#34; data-lang=&#34;mysql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;select&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;from&lt;/span&gt; tb_sku t,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  (&lt;span style=&#34;color:#66d9ef&#34;&gt;select&lt;/span&gt; id &lt;span style=&#34;color:#66d9ef&#34;&gt;from&lt;/span&gt; tb_sku &lt;span style=&#34;color:#66d9ef&#34;&gt;order&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;by&lt;/span&gt; id &lt;span style=&#34;color:#66d9ef&#34;&gt;limit&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;9000000&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;) a 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;where&lt;/span&gt; t.id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; a.id
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;索引创建的原则有哪些&#34;&gt;索引创建的原则有哪些？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;单表超过10万条数据且查询比较频繁的表建立索引&lt;/li&gt;
&lt;li&gt;常常作为查询条件的字段要建立索引&lt;/li&gt;
&lt;li&gt;使用区分度高的列作为索引，尽量建立唯一索引&lt;/li&gt;
&lt;li&gt;字符串类型的字段长度较长可以建立前缀索引&lt;/li&gt;
&lt;li&gt;尽量使用联合索引，减少单列索引&lt;/li&gt;
&lt;li&gt;索引列使用NOT NULL方便优化器确定哪个索引更好用于查询&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;什么情况下索引会失效&#34;&gt;什么情况下索引会失效？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;违反了最左前缀法则&lt;/li&gt;
&lt;li&gt;查询范围右边的列，不能使用索引&lt;/li&gt;
&lt;li&gt;索引列上进行运算操作，索引列失效&lt;/li&gt;
&lt;li&gt;字符串不加单引号，索引失效（索引类型转换导致的失效）&lt;/li&gt;
&lt;li&gt;字符串非尾部匹配，索引失效&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;谈一谈对sql优化的经验&#34;&gt;谈一谈对SQL优化的经验&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;表设计优化
&lt;ul&gt;
&lt;li&gt;我们参考了 阿里开发手册《嵩山版》&lt;/li&gt;
&lt;li&gt;根据实际存储数值长短设计数据类型&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;索引的优化&lt;/li&gt;
&lt;li&gt;SQL语句的优化
&lt;ul&gt;
&lt;li&gt;select 语句务必指明字段名称
&lt;ul&gt;
&lt;li&gt;为了覆盖索引&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;尽量用 union all 代替 union&lt;/li&gt;
&lt;li&gt;避免对 where 子句中对字段进行表达式操作&lt;/li&gt;
&lt;li&gt;能用 innerjoin 就不用 left join , right join。如必须，要以小表为驱动&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;主从复制，读写分离&lt;/li&gt;
&lt;li&gt;分库分表&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;事务的特性详细说一说&#34;&gt;事务的特性详细说一说&lt;/h2&gt;
&lt;h2 id=&#34;并发事务带来哪些问题如何解决这些问题mysql的默认隔离级别是&#34;&gt;并发事务带来哪些问题，如何解决这些问题？MySQL的默认隔离级别是？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;并发事务的问题
&lt;ul&gt;
&lt;li&gt;脏读
&lt;ul&gt;
&lt;li&gt;读已提交&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;不可重复读
&lt;ul&gt;
&lt;li&gt;值问题&lt;/li&gt;
&lt;li&gt;可重复读&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;幻读
&lt;ul&gt;
&lt;li&gt;数量问题&lt;/li&gt;
&lt;li&gt;串行化&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;隔离级别
&lt;ul&gt;
&lt;li&gt;未提交读&lt;/li&gt;
&lt;li&gt;读已提交&lt;/li&gt;
&lt;li&gt;可重复读*&lt;/li&gt;
&lt;li&gt;串行化&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;undo-log-和-redo-log-的区别&#34;&gt;undo log 和 redo log 的区别&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;缓冲池&lt;/li&gt;
&lt;li&gt;数据页&lt;/li&gt;
&lt;li&gt;redo log
&lt;ul&gt;
&lt;li&gt;物理&lt;/li&gt;
&lt;li&gt;持久&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;undo log
&lt;ul&gt;
&lt;li&gt;逻辑&lt;/li&gt;
&lt;li&gt;原子 一致&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;事务的隔离性底层是如何保证的&#34;&gt;事务的隔离性底层是如何保证的？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;锁：排他锁&lt;/li&gt;
&lt;li&gt;MVCC
&lt;ul&gt;
&lt;li&gt;多版本并发控制&lt;/li&gt;
&lt;li&gt;依赖于
&lt;ul&gt;
&lt;li&gt;隐式字段
&lt;ul&gt;
&lt;li&gt;DB_TRX_ID&lt;/li&gt;
&lt;li&gt;DB_ROLL_PTR&lt;/li&gt;
&lt;li&gt;DB_ROW_ID&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;undo log
&lt;ul&gt;
&lt;li&gt;版本链
&lt;ul&gt;
&lt;li&gt;版本链数据访问规则&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;readview
&lt;ul&gt;
&lt;li&gt;快照读
&lt;ul&gt;
&lt;li&gt;Read Committed 每次 select都生成一个快照读&lt;/li&gt;
&lt;li&gt;Repeatable Read 开启事务后第一个 select 语句才是快照读的地方&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;核心字段
&lt;ul&gt;
&lt;li&gt;m_ids&lt;/li&gt;
&lt;li&gt;min_trx_id&lt;/li&gt;
&lt;li&gt;max_trx_id&lt;/li&gt;
&lt;li&gt;creator_trx_id&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;RC隔离级别下，在事务中每次执行快照读时生成 ReadView&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;img style=&#34;background:wheat&#34; src=&#34;https://img.wathan.cn/images/2026/06/cd548aef09e32fd1e14c29fa8745e0e1b60269f31af92b320c83320d44bdedf1.svg&#34;&gt;
&lt;h2 id=&#34;mysql-的主从同步原理&#34;&gt;MySQL 的主从同步原理&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;核心：二进制日志
&lt;ul&gt;
&lt;li&gt;BINLOG
&lt;ul&gt;
&lt;li&gt;DDL&lt;/li&gt;
&lt;li&gt;DML
主数据库在事务提交时，变更记录写入 Binlog
从库 binlog -&amp;gt; 中继日志
从库 中继日志读取事件 -&amp;gt; 从库数据库&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;你们项目用过分库分表吗&#34;&gt;你们项目用过分库分表吗？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;什么时候分库分表
&lt;ul&gt;
&lt;li&gt;单表数据量达到1000W 或者 20GB&lt;/li&gt;
&lt;li&gt;优化解决不了性能问题&lt;/li&gt;
&lt;li&gt;IO、CPU瓶颈&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;如何拆分
&lt;ul&gt;
&lt;li&gt;垂直拆分
&lt;ul&gt;
&lt;li&gt;垂直分库
&lt;ul&gt;
&lt;li&gt;不同表拆分到不同库&lt;/li&gt;
&lt;li&gt;适用于微服务&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;垂直分表
&lt;ul&gt;
&lt;li&gt;不常用字段单独放在一张表&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;水平拆分
&lt;ul&gt;
&lt;li&gt;水平分库
&lt;ul&gt;
&lt;li&gt;一个库的数据拆分到多个库中&lt;/li&gt;
&lt;li&gt;路由规则
&lt;ul&gt;
&lt;li&gt;根据id节点取模&lt;/li&gt;
&lt;li&gt;按id范围路由&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;水平分表
&lt;ul&gt;
&lt;li&gt;一个表的数据拆分到多个表中&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;新的问题
&lt;ul&gt;
&lt;li&gt;分布式事务一致性问题&lt;/li&gt;
&lt;li&gt;跨节点关联查询&lt;/li&gt;
&lt;li&gt;跨节点分页、排序函数&lt;/li&gt;
&lt;li&gt;主键去重&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;解决方案
&lt;ul&gt;
&lt;li&gt;分库分表中间件
&lt;ul&gt;
&lt;li&gt;mycat&lt;/li&gt;
&lt;li&gt;sharding-sphere&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;深入问题&#34;&gt;深入问题&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;为什么 InnoDB 主键建议自增？&lt;/li&gt;
&lt;li&gt;为什么非自增主键会导致页分裂？&lt;/li&gt;
&lt;li&gt;为什么 MyISAM 和 InnoDB 索引结构不同？&lt;/li&gt;
&lt;li&gt;为什么 B+树适合磁盘而红黑树不适合？&lt;/li&gt;
&lt;/ol&gt;</description>
    </item>
    <item>
      <title>JeecgBoot有多厉害？我的看法是</title>
      <link>https://lv-blog.pages.dev/posts/programming/jeecg-boot/</link>
      <pubDate>Mon, 19 Aug 2024 21:33:09 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/jeecg-boot/</guid>
      <description></description>
    </item>
    <item>
      <title>Redis LFU内存淘汰策略细究</title>
      <link>https://lv-blog.pages.dev/posts/programming/redis/redis-memory-eviction-policy-lfu/</link>
      <pubDate>Fri, 19 Jul 2024 13:10:54 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/redis/redis-memory-eviction-policy-lfu/</guid>
      <description>&lt;p&gt;Redis 的 LFU（Least Frequently Used，最不频繁使用）淘汰策略，是在 LRU 基础上做的“升级版”近似算法。它复用了对象头上同一个 24 位的 &lt;code&gt;lru&lt;/code&gt; 字段，通过巧妙的编码和对数计数，用极小的内存代价，实现了对访问频率的近似跟踪。&lt;/p&gt;
&lt;p&gt;下面从存储结构、计数器增减、淘汰决策到参数配置，逐一细究。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;1-24-位字段的位划分&#34;&gt;1. 24 位字段的位划分&lt;/h3&gt;
&lt;p&gt;每个 Redis 对象都有一个 &lt;code&gt;lru&lt;/code&gt; 属性（24 位），在 LFU 模式下，它不再存放秒级时间戳，而是被拆成两段：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; 高 16 位：最后衰减时间（Last Decay Time，单位：分钟）
 低  8 位：对数访问计数器（Logarithmic Counter，范围 0–255）
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;高 16 位&lt;/strong&gt;：存储的是 &lt;code&gt;(server.unixtime / 60) &amp;amp; 0xFFFF&lt;/code&gt;，即当前分钟时间戳的低 16 位。最大表示约 45 天，足够覆盖淘汰场景，即使回绕，只要间隔不超过 45 天就可以正确计算差值。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;低 8 位&lt;/strong&gt;：是一个 0–255 的频率计数器，但它&lt;strong&gt;不是&lt;/strong&gt;访问次数的直接累加，而是经过对数平滑处理的“近似频率”。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当键被访问时，Redis 会调用 &lt;code&gt;updateLFU()&lt;/code&gt;，先根据已流逝的时间衰减计数器，再概率性地递增计数器，最后把新的分钟时间戳和计数器重新编码写回 &lt;code&gt;lru&lt;/code&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;2-计数器递增对数增长&#34;&gt;2. 计数器递增：对数增长&lt;/h3&gt;
&lt;p&gt;为了让 8 位计数器（0–255）既能表示低频也能区分高频，同时不让热门键快速打满，Redis 采用&lt;strong&gt;概率递增&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;递增公式（源码级）：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;double&lt;/span&gt; p &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1.0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; ((counter &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; LFU_INIT_VAL) &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; server.lfu_log_factor &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ((&lt;span style=&#34;color:#a6e22e&#34;&gt;random&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0xFFFF&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; p &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0xFFFF&lt;/span&gt;) counter&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LFU_INIT_VAL&lt;/code&gt; 默认为 5，新键的计数器初始值就是 5。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lfu_log_factor&lt;/code&gt; 是可配置的对数因子，&lt;strong&gt;默认 10&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;随着 &lt;code&gt;counter&lt;/code&gt; 增大，&lt;code&gt;p&lt;/code&gt; 会越来越小，递增越来越难。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;举例（factor = 10 时，典型访问次数与计数器值）：&lt;/p&gt;</description>
    </item>
    <item>
      <title>软考系统架构师 学习</title>
      <link>https://lv-blog.pages.dev/posts/programming/ruan-kao/</link>
      <pubDate>Tue, 18 Jun 2024 12:51:35 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/ruan-kao/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本笔记基于考纲核心知识点整理，配合代码示例和记忆口诀，适合冲刺复习。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;一法律法规与标准化&#34;&gt;一、法律法规与标准化&lt;/h2&gt;
&lt;h3 id=&#34;11-著作权&#34;&gt;1.1 著作权&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;类别&lt;/th&gt;
					&lt;th&gt;内容&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;不受保护&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;政府公文、法律条例、时事新闻&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;受保护&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;演讲稿、编写的图书、软件代码&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;归属时间&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;软件开发完成之日起自动产生&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;保护期限&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;50年（署名权、修改权、完整权永久保护）&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;著作权归属规则：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;谁开发归谁&lt;/li&gt;
&lt;li&gt;员工利用公司资源开发 → 归&lt;strong&gt;公司&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;职务作品无合同 → 归&lt;strong&gt;企业法人&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;改编作品 → 著作权归&lt;strong&gt;改编人&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;处理过程（算法逻辑）不属于软件著作权保护对象&lt;/strong&gt;，只保护代码表达形式。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;受时间限制的权利（50年）：&lt;/strong&gt; 发表权、发行权、展览权、复制权&lt;br&gt;
&lt;strong&gt;永久保护的权利：&lt;/strong&gt; 署名权、修改权、保护作品完整权&lt;/p&gt;
&lt;h3 id=&#34;12-其他知识产权&#34;&gt;1.2 其他知识产权&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;商标权&lt;/strong&gt;：注册完成后才享有；保护对象为软件注册商标&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;专利权&lt;/strong&gt;：专利注册完成后才享有&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二软件工程&#34;&gt;二、软件工程&lt;/h2&gt;
&lt;h3 id=&#34;21-软件开发模型对比&#34;&gt;2.1 软件开发模型对比&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;模型&lt;/th&gt;
					&lt;th&gt;适用场景&lt;/th&gt;
					&lt;th&gt;核心特征&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;瀑布模型&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;需求明确固定&lt;/td&gt;
					&lt;td&gt;阶段严格顺序，不可逆&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;增量模型&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;需求部分明确，需快速交付核心&lt;/td&gt;
					&lt;td&gt;分批次交付模块&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;原型模型&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;需求模糊，用户难以描述&lt;/td&gt;
					&lt;td&gt;先做原型再开发目标软件&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;螺旋模型&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;大型复杂高风险项目&lt;/td&gt;
					&lt;td&gt;每轮增加&lt;strong&gt;风险评估&lt;/strong&gt;环节&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;喷泉模型&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;面向对象开发&lt;/td&gt;
					&lt;td&gt;无严格阶段划分，阶段可交叉迭代&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;V模型&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;可靠性要求高&lt;/td&gt;
					&lt;td&gt;开发与测试一一对应&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;W模型&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;质量要求高&lt;/td&gt;
					&lt;td&gt;开发与测试&lt;strong&gt;同步进行&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;瀑布模型阶段：
需求分析 → 系统设计 → 详细设计 → 编码 → 测试 → 维护
（每个阶段完成后才进入下一阶段）

螺旋模型四象限：
① 制定计划  ② 风险分析
③ 实施工程  ④ 客户评估
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;22-敏捷开发方法对比&#34;&gt;2.2 敏捷开发方法对比&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;方法&lt;/th&gt;
					&lt;th&gt;核心理念&lt;/th&gt;
					&lt;th&gt;关键特征&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;XP（极限编程）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;把传统开发做到极致精简&lt;/td&gt;
					&lt;td&gt;结对编程、测试先行、持续集成&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;SCRUM&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;短周期冲刺&lt;/td&gt;
					&lt;td&gt;三会议（站会/计划/回顾），需求按&lt;strong&gt;商业价值&lt;/strong&gt;排序&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;水晶开发&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;以人为本&lt;/td&gt;
					&lt;td&gt;最轻量灵活，重团队协作，文档少&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;FDD&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;特性驱动&lt;/td&gt;
					&lt;td&gt;五步：建模→功能清单→规划→设计→实现&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;ASD&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;适应性开发&lt;/td&gt;
					&lt;td&gt;猜测→协作→复盘，三个非线性阶段&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;DSDM&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;动态系统开发&lt;/td&gt;
					&lt;td&gt;八条原则，聚焦业务价值按时交付&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;开放源码&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;全球协作&lt;/td&gt;
					&lt;td&gt;高并行排障，代码公开&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;SCRUM 三大会议：&lt;/strong&gt; 每日站会、迭代计划会、复盘回顾会&lt;/p&gt;</description>
    </item>
    <item>
      <title>ElasticSearch 学习</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/elasticsearch/</link>
      <pubDate>Sat, 18 May 2024 12:51:05 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/elasticsearch/</guid>
      <description>&lt;h2 id=&#34;1-基础篇&#34;&gt;1. 基础篇&lt;/h2&gt;
&lt;h3 id=&#34;11-起源lucene&#34;&gt;1.1 起源：Lucene&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lucene&lt;/strong&gt;：Apache 开源的 Java 全文搜索引擎类库。&lt;/li&gt;
&lt;li&gt;优势：易扩展、高性能（纯 Java，可嵌入）。&lt;/li&gt;
&lt;li&gt;缺点：使用复杂，需处理索引创建、查询解析等底层细节，无分布式支持。&lt;/li&gt;
&lt;li&gt;Elasticsearch 基于 Lucene 构建，提供分布式、易用的 RESTful API。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;12-技术栈elk&#34;&gt;1.2 技术栈（ELK）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Elasticsearch&lt;/strong&gt;：存储、搜索和分析引擎。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logstash&lt;/strong&gt;：服务器端数据处理管道，采集、转换数据后发送至 ES。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kibana&lt;/strong&gt;：可视化平台，制作图表、仪表板，管理 ES。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Beats&lt;/strong&gt;：轻量型数据采集器，发送到 Logstash 或 ES。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;13-使用-docker-安装&#34;&gt;1.3 使用 Docker 安装&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Elasticsearch&lt;/strong&gt;（单节点）：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker run -d --name es &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -e &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ES_JAVA_OPTS=-Xms512m -Xmx512m&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -e &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;discovery.type=single-node&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -v es-data:/usr/share/elasticsearch/data &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -v es-plugins:/usr/share/elasticsearch/plugins &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  --privileged &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  --network testNet &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -p 9200:9200 -p 9300:9300 &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  elasticsearch:7.12.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;9200：HTTP API 端口&lt;/li&gt;
&lt;li&gt;9300：内部节点通信端口&lt;/li&gt;
&lt;li&gt;&lt;code&gt;discovery.type=single-node&lt;/code&gt;：单节点模式（测试用）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Kibana&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker run -d --name kibana &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -e ELASTICSEARCH_HOSTS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;http://es:9200 &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  --network&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;testNet &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -p 5601:5601 &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  kibana:7.12.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;14-倒排索引inverted-index&#34;&gt;1.4 倒排索引（Inverted Index）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;正向索引&lt;/strong&gt;：文档 ID → 文档内容。适合根据 ID 精确查找，但做模糊搜索需遍历所有文档，效率低。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;倒排索引&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;文档（Document）&lt;/strong&gt;：ES 中存储的一条 JSON 数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;词条（Term）&lt;/strong&gt;：文档经过分词后的最小单元。&lt;/li&gt;
&lt;li&gt;结构：词条 → 文档 ID 列表（及位置、频率等）。&lt;/li&gt;
&lt;li&gt;优点：快速定位包含某个词条的所有文档，实现高效全文搜索。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;15-分词器analyzer&#34;&gt;1.5 分词器（Analyzer）&lt;/h3&gt;
&lt;p&gt;将文本拆分为词条（term）的组件，由三部分组成：&lt;/p&gt;</description>
    </item>
    <item>
      <title>AWS 学习</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/aws/</link>
      <pubDate>Thu, 18 Apr 2024 12:48:03 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/aws/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;面向系统架构师认证，结合 Java 后端视角整理。核心思路：&lt;strong&gt;每个服务解决什么痛点、何时选它、和类似服务怎么区分&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;一存储-storage&#34;&gt;一、存储 Storage&lt;/h2&gt;
&lt;h3 id=&#34;11-三种存储类型对比&#34;&gt;1.1 三种存储类型对比&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;类型&lt;/th&gt;
					&lt;th&gt;代表服务&lt;/th&gt;
					&lt;th&gt;访问单元&lt;/th&gt;
					&lt;th&gt;典型场景&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;块存储&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;EBS, EC2 Instance Store&lt;/td&gt;
					&lt;td&gt;数据块（Block）&lt;/td&gt;
					&lt;td&gt;数据库、OS 磁盘&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;文件存储&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;EFS, FSx&lt;/td&gt;
					&lt;td&gt;文件/目录树&lt;/td&gt;
					&lt;td&gt;多实例共享、NFS/SMB挂载&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;对象存储&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;S3&lt;/td&gt;
					&lt;td&gt;对象（Object + Key）&lt;/td&gt;
					&lt;td&gt;静态资源、备份、数据湖&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;块存储  → 像本地硬盘，OS看到的是裸设备，自己格式化挂载
文件存储 → 像 NAS，多台机器可以同时 mount 同一个目录
对象存储 → 像 HTTP PUT/GET 的 Key-Value，无目录概念，靠前缀模拟
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h3 id=&#34;12-amazon-s3&#34;&gt;1.2 Amazon S3&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;核心功能速查：&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;功能&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
					&lt;th&gt;常见考点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Versioning&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;同一 Key 保留多个历史版本&lt;/td&gt;
					&lt;td&gt;开启后才能用 CRR / MFA Delete&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;CRR（跨区域复制）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;异步复制到另一 Region&lt;/td&gt;
					&lt;td&gt;灾备 DR、降低延迟&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Transfer Acceleration&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;通过 CloudFront 边缘节点加速上传&lt;/td&gt;
					&lt;td&gt;上传到遥远 Region 时使用&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Lifecycle Policy&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;对象按年龄自动迁移存储类&lt;/td&gt;
					&lt;td&gt;节省成本核心手段&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;S3 File Gateway&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;本地 SMB/NFS 映射到 S3&lt;/td&gt;
					&lt;td&gt;混合云文件迁移&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Intelligent-Tiering&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;自动在 Standard ↔ IA 间切换&lt;/td&gt;
					&lt;td&gt;访问模式不可预测时使用&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;S3 存储类选择决策树：&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Spring Cloud 学习</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/spring-cloud/</link>
      <pubDate>Mon, 18 Mar 2024 12:46:51 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/spring-cloud/</guid>
      <description>&lt;h2 id=&#34;1-服务拆分与远程调用&#34;&gt;1. 服务拆分与远程调用&lt;/h2&gt;
&lt;h3 id=&#34;11-为什么要拆分服务&#34;&gt;1.1 为什么要拆分服务？&lt;/h3&gt;
&lt;p&gt;单体应用随业务增长面临：部署慢、扩展性差、技术栈固化等问题。微服务将其拆分为&lt;strong&gt;独立部署、独立扩缩容&lt;/strong&gt;的小服务，每个服务只负责一个业务域。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;拆分原则：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单一职责：每个服务只做一件事&lt;/li&gt;
&lt;li&gt;高内聚低耦合：服务内部紧密，服务之间松散&lt;/li&gt;
&lt;li&gt;数据独立：每个服务拥有独立数据库&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;12-用户登录流程微服务视角&#34;&gt;1.2 用户登录流程（微服务视角）&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Client → Gateway（鉴权） → 业务微服务A → 微服务B（OpenFeign）
                ↓
           Nacos（服务发现）
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;13-resttemplate--微服务间原始调用&#34;&gt;1.3 RestTemplate — 微服务间原始调用&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;RestTemplate&lt;/code&gt; 是 Spring 提供的 HTTP 客户端，可用于微服务间调用，但&lt;strong&gt;代码繁琐、不支持负载均衡&lt;/strong&gt;，是 OpenFeign 出现前的过渡方案。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 注册为 Bean，并开启负载均衡&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@Bean&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@LoadBalanced&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; RestTemplate &lt;span style=&#34;color:#a6e22e&#34;&gt;restTemplate&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; RestTemplate();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 调用方式（服务名替代 IP:Port）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;String url &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://user-service/api/users/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; userId;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;User user &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; restTemplate.&lt;span style=&#34;color:#a6e22e&#34;&gt;getForObject&lt;/span&gt;(url, User.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;⚠️ RestTemplate 已逐渐被 OpenFeign 取代，生产中优先选择 OpenFeign。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;2-服务治理--nacos-注册中心&#34;&gt;2. 服务治理 — Nacos 注册中心&lt;/h2&gt;
&lt;h3 id=&#34;21-解决的问题&#34;&gt;2.1 解决的问题&lt;/h3&gt;
&lt;p&gt;微服务实例 IP / 端口动态变化，调用方无法硬编码地址。注册中心提供：&lt;/p&gt;</description>
    </item>
    <item>
      <title>SSM框架 学习</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/ssm/</link>
      <pubDate>Sun, 18 Feb 2024 12:40:44 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/ssm/</guid>
      <description>&lt;h2 id=&#34;一spring-ioc-容器&#34;&gt;一、Spring IoC 容器&lt;/h2&gt;
&lt;h3 id=&#34;11-容器体系结构&#34;&gt;1.1 容器体系结构&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;BeanFactory（顶层接口）
    └── ApplicationContext（常用接口，扩展了BF）
            ├── ClassPathXmlApplicationContext（XML配置）
            ├── FileSystemXmlApplicationContext（文件路径XML）
            └── AnnotationConfigApplicationContext（注解配置）
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;BeanFactory vs ApplicationContext 核心区别：&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;特性&lt;/th&gt;
					&lt;th&gt;BeanFactory&lt;/th&gt;
					&lt;th&gt;ApplicationContext&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Bean 初始化时机&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;懒加载&lt;/strong&gt;（第一次 getBean 时）&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;饿加载&lt;/strong&gt;（容器启动时）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;功能&lt;/td&gt;
					&lt;td&gt;基础 IoC&lt;/td&gt;
					&lt;td&gt;IoC + 事件发布 + 国际化 + AOP等&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;使用场景&lt;/td&gt;
					&lt;td&gt;资源极度受限的嵌入式&lt;/td&gt;
					&lt;td&gt;99% 的业务场景&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ApplicationContext 为什么没有 close()？&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;ApplicationContext&lt;/code&gt; 接口本身不定义 &lt;code&gt;close()&lt;/code&gt;，是为了保持接口的通用性（不是所有容器都能/需要被关闭，如 Web 容器）。但其实现类 &lt;code&gt;AbstractApplicationContext&lt;/code&gt; 实现了 &lt;code&gt;Closeable&lt;/code&gt;，可以强转后调用，或用 &lt;code&gt;ConfigurableApplicationContext&lt;/code&gt; 接口接收。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&#34;12-延迟加载lazy-loading&#34;&gt;1.2 延迟加载（Lazy Loading）&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 注解方式：@Lazy 让 Bean 在第一次被使用时才初始化&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@Bean&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@Lazy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; HeavyService &lt;span style=&#34;color:#a6e22e&#34;&gt;heavyService&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HeavyService();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// XML方式：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// &amp;lt;bean id=&amp;#34;heavyService&amp;#34; class=&amp;#34;...&amp;#34; lazy-init=&amp;#34;true&amp;#34;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：初始化代价高、启动时不一定用到的 Bean（如某些连接池、第三方SDK客户端）。&lt;/p&gt;</description>
    </item>
    <item>
      <title>MyBatis-Plus 学习</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/mybatisplus/</link>
      <pubDate>Tue, 16 Jan 2024 15:38:37 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/mybatisplus/</guid>
      <description>&lt;h2 id=&#34;1-简介&#34;&gt;1. 简介&lt;/h2&gt;
&lt;p&gt;MyBatis-Plus（简称 MP）是一个 MyBatis 的增强工具，在 MyBatis 的基础上只做增强不做改变，为简化开发、提高效率而生。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心特点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;无侵入&lt;/strong&gt;：引入 MP 不会对现有 MyBatis 工程产生影响，犹如丝般顺滑。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;损耗小&lt;/strong&gt;：启动即会自动注入基本 CRUD，性能基本无损耗。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;强大的 CRUD 操作&lt;/strong&gt;：内置通用 Mapper、通用 Service，仅通过少量配置即可实现单表大部分 CRUD 操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支持 Lambda 形式调用&lt;/strong&gt;：通过 Lambda 表达式，安全高效的编写查询条件，防止字段名误写。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内置代码生成器&lt;/strong&gt;：通过少量配置即可生成 Mapper、Service、Controller 等代码。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内置分页插件&lt;/strong&gt;：基于 MyBatis 物理分页，开发者无需关心具体操作，配置后即可使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;官网&lt;/strong&gt;：&lt;a href=&#34;https://baomidou.com/&#34;&gt;https://baomidou.com/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;2-基本用法&#34;&gt;2. 基本用法&lt;/h2&gt;
&lt;h3 id=&#34;21-引入依赖&#34;&gt;2.1 引入依赖&lt;/h3&gt;
&lt;p&gt;在 Maven 项目 &lt;code&gt;pom.xml&lt;/code&gt; 中添加：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.baomidou&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;mybatis-plus-boot-starter&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.5.3.1&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;!-- 请按最新版本 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果是传统 Spring 项目，可引入 &lt;code&gt;mybatis-plus&lt;/code&gt; 核心依赖并自行配置。通常 Spring Boot 项目直接使用 starter。&lt;/p&gt;
&lt;h3 id=&#34;22-定义实体类&#34;&gt;2.2 定义实体类&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@Data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;User&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Long id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; String name;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Integer age;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; String email;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;23-编写-mapper-接口&#34;&gt;2.3 编写 Mapper 接口&lt;/h3&gt;
&lt;p&gt;继承 &lt;code&gt;BaseMapper&amp;lt;T&amp;gt;&lt;/code&gt; 即可获得 CRUD 能力：&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
