-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
291 lines (265 loc) · 38.7 KB
/
Copy pathindex.html
File metadata and controls
291 lines (265 loc) · 38.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0,viewport-fit=cover"><title>Lavigne-yang.Blog</title><meta name="author" content="Lavigne-yang"><meta name="copyright" content="Lavigne-yang"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="ffffff"><meta name="description" content="专注于知识积累">
<meta property="og:type" content="website">
<meta property="og:title" content="Lavigne-yang.Blog">
<meta property="og:url" content="https://lavyoung.github.io/index.html">
<meta property="og:site_name" content="Lavigne-yang.Blog">
<meta property="og:description" content="专注于知识积累">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://lavyoung.github.io/img/avatar.jpg">
<meta property="article:author" content="Lavigne-yang">
<meta property="article:tag" content="Lavigne-yang.Blog">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://lavyoung.github.io/img/avatar.jpg"><script type="application/ld+json">{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "Lavigne-yang.Blog",
"alternateName": [
"lavyoung.github.io"
],
"url": "https://lavyoung.github.io/"
}</script><link rel="shortcut icon" href="/img/blog-black.svg"><link rel="canonical" href="https://lavyoung.github.io/index.html"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css"><script>
(() => {
const saveToLocal = {
set: (key, value, ttl) => {
if (!ttl) return
const expiry = Date.now() + ttl * 86400000
localStorage.setItem(key, JSON.stringify({ value, expiry }))
},
get: key => {
const itemStr = localStorage.getItem(key)
if (!itemStr) return undefined
const { value, expiry } = JSON.parse(itemStr)
if (Date.now() > expiry) {
localStorage.removeItem(key)
return undefined
}
return value
}
}
window.btf = {
saveToLocal,
getScript: (url, attr = {}) => new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = url
script.async = true
Object.entries(attr).forEach(([key, val]) => script.setAttribute(key, val))
script.onload = script.onreadystatechange = () => {
if (!script.readyState || /loaded|complete/.test(script.readyState)) resolve()
}
script.onerror = reject
document.head.appendChild(script)
}),
getCSS: (url, id) => new Promise((resolve, reject) => {
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = url
if (id) link.id = id
link.onload = link.onreadystatechange = () => {
if (!link.readyState || /loaded|complete/.test(link.readyState)) resolve()
}
link.onerror = reject
document.head.appendChild(link)
}),
addGlobalFn: (key, fn, name = false, parent = window) => {
if (!false && key.startsWith('pjax')) return
const globalFn = parent.globalFn || {}
globalFn[key] = globalFn[key] || {}
globalFn[key][name || Object.keys(globalFn[key]).length] = fn
parent.globalFn = globalFn
}
}
const activateDarkMode = () => {
document.documentElement.setAttribute('data-theme', 'dark')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
}
}
const activateLightMode = () => {
document.documentElement.setAttribute('data-theme', 'light')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', 'ffffff')
}
}
btf.activateDarkMode = activateDarkMode
btf.activateLightMode = activateLightMode
const theme = saveToLocal.get('theme')
theme === 'dark' ? activateDarkMode() : theme === 'light' ? activateLightMode() : null
const asideStatus = saveToLocal.get('aside-status')
if (asideStatus !== undefined) {
document.documentElement.classList.toggle('hide-aside', asideStatus === 'hide')
}
const detectApple = () => {
if (/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)) {
document.documentElement.classList.add('apple')
}
}
detectApple()
})()
</script><script>const GLOBAL_CONFIG = {
root: '/',
algolia: undefined,
localSearch: undefined,
translate: {"defaultEncoding":2,"translateDelay":0,"msgToTraditionalChinese":"繁","msgToSimplifiedChinese":"簡"},
highlight: {"plugin":"highlight.js","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false,"highlightFullpage":false,"highlightMacStyle":true},
copy: {
success: '复制成功',
error: '复制失败',
noSupport: '浏览器不支持'
},
relativeDate: {
homepage: false,
post: false
},
runtime: '天',
dateSuffix: {
just: '刚刚',
min: '分钟前',
hour: '小时前',
day: '天前',
month: '个月前'
},
copyright: undefined,
lightbox: 'null',
Snackbar: undefined,
infinitegrid: {
js: 'https://cdn.jsdelivr.net/npm/@egjs/infinitegrid/dist/infinitegrid.min.js',
buttonText: '加载更多'
},
isPhotoFigcaption: false,
islazyloadPlugin: false,
isAnchor: false,
percent: {
toc: true,
rightside: true,
},
autoDarkmode: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
title: 'Lavigne-yang.Blog',
isHighlightShrink: false,
isToc: false,
pageType: 'home'
}</script><meta name="generator" content="Hexo 7.3.0"></head><body><div class="bg-animation" id="web_bg" style="background-image: url(/img/top_img.jpg);"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img text-center"><img src="/img/avatar.jpg" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="site-data text-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">22</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">10</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">4</div></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div></div></div></div><div class="page" id="body-wrap"><header class="full_page fixed" id="page-header" style="background-image: url(/img/top_img.jpg);"><nav id="nav"><span id="blog-info"><a class="nav-site-title" href="/"><img class="site-icon" src="/img/blog-black.svg" alt="Logo"><span class="site-name">Lavigne-yang.Blog</span></a></span><div id="menus"><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div></div><div id="toggle-menu"><span class="site-page"><i class="fas fa-bars fa-fw"></i></span></div></div></nav><div id="site-info"><h1 id="site-title">Lavigne-yang.Blog</h1><div id="site-subtitle"><span id="subtitle"></span></div><div id="site_social_icons"><a class="social-icon" href="https://github.com/Lavigne-yang" target="_blank" title="Github"><i class="fab fa-github" style="color: #24292e;"></i></a><a class="social-icon" href="mailto:[email protected]" target="_blank" title="Email"><i class="fas fa-envelope" style="color: #22205e;"></i></a></div></div><div id="scroll-down"><i class="fas fa-angle-down scroll-down-effects"></i></div></header><main class="layout" id="content-inner"><div class="recent-posts nc" id="recent-posts"><div class="recent-post-items"><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2026/02/27/LinkLLM-%E5%AF%B9%E8%AF%9D%E4%B8%AD%E6%96%AD%E6%B5%81%E7%A8%8B%E8%AE%BE%E8%AE%A1%E4%B8%8E%E5%AE%9E%E7%8E%B0/" title="LinkLLM Server 对话中断流程设计与实现">LinkLLM Server 对话中断流程设计与实现</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2026-02-27T06:30:00.000Z" title="发表于 2026-02-27 14:30:00">2026-02-27</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/AI/">AI</a></span></div><div class="content">前言在构建 LLM 服务网关时,流式响应(SSE)已经成为标配功能。用户可以实时看到 AI 的生成过程,获得更好的交互体验。然而,流式响应也带来了新的挑战:如何优雅地处理用户中断?如何在网络断开时正确清理资源?如何保证中断时已生成的内容不丢失? 本文将分享 LinkLLM 项目中对话中断流程的设计与实现,介绍如何构建一个企业级的流式对话中断机制。 问题背景流式对话的中断场景在实际生产环境中,流式对话面临多种中断场景: 123456789101112131415┌─────────────────────────────────────────────────────────────┐│ 流式对话中断场景 │├─────────────────────────────────────────────────────────────┤│ 场景1: 用户主动中断 ││ 用户点击停止按钮 → 需要立即停止生成 ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2025/06/09/Nacos%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86%EF%BC%88%E4%B8%80%EF%BC%89/" title="Nacos基本原理(一)">Nacos基本原理(一)</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2025-06-09T12:14:21.000Z" title="发表于 2025-06-09 20:14:21">2025-06-09</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/%E6%8A%80%E6%9C%AF/">技术</a></span></div><div class="content">重点关注naming/config模块、基于plugin模块开发自定义插件(如数据源适配)、扩展core模块的通信框架(gRPC/HTTP) 版本 默认协议 特点 配置方式 1.x HTTP 短连接,性能低 无需额外配置 2.x gRPC 长连接,性能提升 10 倍 临时实例自动启用(ephemeral=true) 3.x gRPC + QUIC 支持 AI Agent 场景,强化安全隔离 默认启用,可通过插件扩展协议 关键版本升级点: 2.0 gRPC 替代 HTTP 提升吞吐量。 插件化架构(如自定义鉴权模块) 3.0 安全增强:分离控制台 API 与服务 API 端口,支持命名空间统一管理 AI 支持:优化轻量化 Agent 的注册发现机制(如 Serverless 场景) 服务注册和发现(健康检查)服务注册机制 客户端自动注册触发机制 入口:Spring Boot 项目引入 spring-cloud-starter-alibaba-nacos-discovery 后,通过 spring.factories 加载自动...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2025/06/09/SpringBoot%E5%90%AF%E5%8A%A8%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90/" title="SpringBoot启动原理解析">SpringBoot启动原理解析</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2025-06-09T12:14:21.000Z" title="发表于 2025-06-09 20:14:21">2025-06-09</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/%E6%8A%80%E6%9C%AF/">技术</a></span></div><div class="content">核心流程 启动入口:SpringApplication.run() 创建 SpringApplication 实例,初始化 ApplicationContext(默认 AnnotationConfigApplicationContext)。 加载 META-INF/spring.factories 中的 ApplicationContextInitializer 和 ApplicationListener。 准备环境(Environment) 读取默认配置application.yml及命令行参数。 配置 Profiles``prod)。 创建并刷新 ApplicationContext 调用 AbstractApplicationContext.refresh(),核心流程: Bean 定义加载:扫描 @Component、@Service 等注解类。 Bean 实例化:通过 BeanFactory 创建单例 Bean。 依赖注入:处理 @Autowired、@Resource 等注解。 初始化回调:执行 @PostConstruct、InitializingBean...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2025/05/28/%E4%B8%9A%E5%8A%A1%E5%9C%BA%E6%99%AF/" title="业务方案总结">业务方案总结</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2025-05-28T09:24:23.000Z" title="发表于 2025-05-28 17:24:23">2025-05-28</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/%E6%96%B9%E6%A1%88/">方案</a></span></div><div class="content">Q:Redis和数据库的缓存一致性保证A: 方案如下: 更新数据库之后删除缓存(旁路缓存模式) 并发情况下可采用延迟双删策略 或者实现canal客户端订阅数据变更,更新缓存 适合:商品详情页场景,读多写少的场景 先更新缓存再更新数据库(异步更新) 更新缓存成功采用消息队列更新数据(消费幂等性保证) 场景:秒杀 双写操作 同时更新Redis和数据库,可以使用事务保证(分布式事务方案,事务补偿机制) 场景:积分 数据回写 优先更新缓存,缓存数据定期更新到数据库(Redis集群和持久化机制) 场景:广告计费系统,点赞 Q:分布式锁实现方案A: 本地同步锁 分布式锁setNX 设置超时时间 redission看门狗机制,读写锁 redisssion redlock 解决锁的高一致性问题 Q:如何快速定位线上OOMA:出现的原因: 一次性申请的对象数量过多:如查询返回结果过大 内存资源耗尽未释放:如何jdbc连接、文件资源 本身资源不够:jmap -heap PID 查看堆信息 方案: 预先设置-XX:+HeapDumpOnOutOfMemoryError...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2025/04/11/LeetCode%E7%AE%97%E6%B3%95%E9%A2%98%EF%BC%88%E4%BA%8C%EF%BC%89/" title="算法热题(二)">算法热题(二)</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2025-04-11T09:24:23.000Z" title="发表于 2025-04-11 17:24:23">2025-04-11</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/%E7%AE%97%E6%B3%95/">算法</a></span></div><div class="content">二叉树1. 二叉树的中序遍历 (简)给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。 进阶: 递归算法很简单,你可以通过迭代算法完成吗? 提示: 树中节点数目在范围 [0, 100] 内 100 <= Node.val <= 100 示例:  12输入:root = [1,null,2,3]输出:[1,3,2] 代码: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2025/03/28/LeetCode%E7%AE%97%E6%B3%95%E9%A2%98%EF%BC%88%E4%B8%80%EF%BC%89/" title="算法热题(一)">算法热题(一)</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2025-03-28T09:24:23.000Z" title="发表于 2025-03-28 17:24:23">2025-03-28</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/%E7%AE%97%E6%B3%95/">算法</a></span></div><div class="content">哈希1. 两数之和给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 *target* 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。 你可以按任意顺序返回答案。 提示: 2 <= nums.length <= 104 109 <= nums[i] <= 109 109 <= target <= 109 只会存在一个有效答案 示例: 1234567输入:nums = [2,7,11,15], target = 9输出:[0,1]解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 输入:nums = [3,2,4], target = 6输出:[1,2]解释:因为 nums[1] + nums[2] == 6 , 返回[1, 2] 代码: 123456789101112131415161718192021/** * **进阶**:**时间复杂度小于 O(n2) 的算法解决此问题吗?** * 1. 使...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2025/02/09/%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F/" title="命令模式">命令模式</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2025-02-09T02:33:23.000Z" title="发表于 2025-02-09 10:33:23">2025-02-09</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/%E6%8A%80%E6%9C%AF/">技术</a></span></div><div class="content">基本概念命令模式:一种行为型设计模式,它将“请求”封装为对象,使发送请求的客户端与执行请求的接收者解耦。通过这种封装,可以让请求参数化、排队执行、记录日志或支持撤销操作。 核心结构 命令接口(Command):定义执行命令的方法(如execute())。 具体命令(Concrete Command):实现命令接口,绑定接收者和具体操作。 接收者(Receiver):执行命令的具体对象,知道如何完成命令对应的操作。 调用者(Invoker):持有命令对象,通过调用命令的方法来触发请求。 客户端(Client):创建具体命令并设置其接收者,将命令交给调用者。 示例说明场景:遥控器控制家电 命令接口 1234567// 命令接口interface Command { void execute(); // 执行命令 void undo(); // 撤销命令(可选)} 接收者:电灯 1234567891011class Light { void on() { System.o...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2025/01/11/%E8%B4%A3%E4%BB%BB%E9%93%BE%E6%A8%A1%E5%BC%8F/" title="责任链模式">责任链模式</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2025-01-11T04:03:22.000Z" title="发表于 2025-01-11 12:03:22">2025-01-11</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/%E6%8A%80%E6%9C%AF/">技术</a></span></div><div class="content">基本概念责任链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。 核心思想:请求沿着处理者链传递,每个处理者决定是处理请求还是将其传递给下一个处理者,形成一个灵活的请求处理机制。 核心结构 Handler(处理者接口):定义处理请求的接口,包含设置下一个处理者和处理请求的方法 ConcreteHandler(具体处理者):实现处理者接口,决定是否处理请求,若不能处理则传递给下一个处理者 Client(客户端):创建处理链,并向链的起始端发送请求 示例说明场景:员工请假审批系统,不同级别领导处理不同天数的请假申请 组长:处理1天内的请假 部门经理:处理3天内的请假 总经理:处理7天内的请假 超过7天的请假不予批准 处理者接口 123456789101112public abstract class Approver { protected Approver nextApprover; // 下一个处理者 // 设置下一个处理者 publi...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2024/12/11/%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F/" title="观察者模式">观察者模式</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2024-12-11T01:43:23.000Z" title="发表于 2024-12-11 09:43:23">2024-12-11</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/%E6%8A%80%E6%9C%AF/">技术</a></span></div><div class="content">基本概念观察者模式:一种行为型设计模式,定义了对象之间的一对多依赖关系。当一个对象(主题)的状态发生改变时,所有依赖它的对象(观察者)都会自动收到通知并更新。 核心思想: 主题(Subject)维护观察者(Observer)列表 主题状态变化时,主动通知所有观察者 观察者无需知道其他观察者的存在,只关注主题更新 核心结构 主题(Subject):定义观察者注册/移除方法,维护观察者列表,状态变化时通知观察者。 观察者(Observer):定义更新接口,接收主题通知并作出响应。 具体主题(ConcreteSubject):实现主题接口,维护具体状态,状态变化时通知观察者。 具体观察者(ConcreteObserver):实现观察者接口,存储与主题相关的状态,响应通知。 示例说明场景:股票价格监控系统,当股票价格变化时,自动通知所有关注该股票的投资者 定义主题接口 123456789public interface Stock { void attach(Investor investor); // 注册观察者 void deta...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2024/11/14/%E5%A4%8D%E5%90%88%E6%A8%A1%E5%BC%8F/" title="复合模式">复合模式</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2024-11-14T03:03:14.000Z" title="发表于 2024-11-14 11:03:14">2024-11-14</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/%E6%8A%80%E6%9C%AF/">技术</a></span></div><div class="content">基本概念复合模式:并非单一的设计模式,而是多种设计模式的组合应用,通过协同多种模式解决复杂场景问题。 核心思想:根据实际需求,将不同设计模式的优势结合,形成更强大的解决方案,同时避免单一模式的局限性。 示例说明典型复合模式示例:MVC架构(Model-View-Controller) MVC是最经典的复合模式之一,融合了多种设计模式: 观察者模式:View监听Model变化,自动更新界面 策略模式:Controller作为不同逻辑处理的策略 工厂模式:创建Model、View组件 责任链模式:请求在Controller链中传递处理 Model(数据模型,使用观察者模式) 123456789101112131415161718192021222324class UserModel { private String name; private List<View> views = new ArrayList<>();public void addView(View view) { views.add(vie...</div></div></div></div><nav id="pagination"><div class="pagination"><span class="page-number current">1</span><a class="page-number" href="/page/2/#content-inner">2</a><a class="page-number" href="/page/3/#content-inner">3</a><a class="extend next" rel="next" href="/page/2/#content-inner"><i class="fas fa-chevron-right fa-fw"></i></a></div></nav></div><div class="aside-content" id="aside-content"><div class="card-widget card-info text-center"><div class="avatar-img"><img src="/img/avatar.jpg" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info-name">Lavigne-yang</div><div class="author-info-description">专注于知识积累</div><div class="site-data"><a href="/archives/"><div class="headline">文章</div><div class="length-num">22</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">10</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">4</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/Lavigne-yang"><i class="fab fa-github"></i><span>关注</span></a><div class="card-info-social-icons"><a class="social-icon" href="https://github.com/Lavigne-yang" target="_blank" title="Github"><i class="fab fa-github" style="color: #24292e;"></i></a><a class="social-icon" href="mailto:[email protected]" target="_blank" title="Email"><i class="fas fa-envelope" style="color: #22205e;"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">如有不足,欢迎斧正[抱拳]</div></div><div class="sticky_layout"><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/2026/02/27/LinkLLM-%E5%AF%B9%E8%AF%9D%E4%B8%AD%E6%96%AD%E6%B5%81%E7%A8%8B%E8%AE%BE%E8%AE%A1%E4%B8%8E%E5%AE%9E%E7%8E%B0/" title="LinkLLM Server 对话中断流程设计与实现"><img src="/img/default_img.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="LinkLLM Server 对话中断流程设计与实现"/></a><div class="content"><a class="title" href="/2026/02/27/LinkLLM-%E5%AF%B9%E8%AF%9D%E4%B8%AD%E6%96%AD%E6%B5%81%E7%A8%8B%E8%AE%BE%E8%AE%A1%E4%B8%8E%E5%AE%9E%E7%8E%B0/" title="LinkLLM Server 对话中断流程设计与实现">LinkLLM Server 对话中断流程设计与实现</a><time datetime="2026-02-27T06:30:00.000Z" title="发表于 2026-02-27 14:30:00">2026-02-27</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2025/06/09/Nacos%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86%EF%BC%88%E4%B8%80%EF%BC%89/" title="Nacos基本原理(一)"><img src="/img/article/nasa_the_blue_marble.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Nacos基本原理(一)"/></a><div class="content"><a class="title" href="/2025/06/09/Nacos%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86%EF%BC%88%E4%B8%80%EF%BC%89/" title="Nacos基本原理(一)">Nacos基本原理(一)</a><time datetime="2025-06-09T12:14:21.000Z" title="发表于 2025-06-09 20:14:21">2025-06-09</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2025/06/09/SpringBoot%E5%90%AF%E5%8A%A8%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90/" title="SpringBoot启动原理解析"><img src="/img/article/nasa_the_blue_marble.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="SpringBoot启动原理解析"/></a><div class="content"><a class="title" href="/2025/06/09/SpringBoot%E5%90%AF%E5%8A%A8%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90/" title="SpringBoot启动原理解析">SpringBoot启动原理解析</a><time datetime="2025-06-09T12:14:21.000Z" title="发表于 2025-06-09 20:14:21">2025-06-09</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2025/05/28/%E4%B8%9A%E5%8A%A1%E5%9C%BA%E6%99%AF/" title="业务方案总结"><img src="/img/article/nasa_the_blue_marble.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="业务方案总结"/></a><div class="content"><a class="title" href="/2025/05/28/%E4%B8%9A%E5%8A%A1%E5%9C%BA%E6%99%AF/" title="业务方案总结">业务方案总结</a><time datetime="2025-05-28T09:24:23.000Z" title="发表于 2025-05-28 17:24:23">2025-05-28</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2025/04/11/LeetCode%E7%AE%97%E6%B3%95%E9%A2%98%EF%BC%88%E4%BA%8C%EF%BC%89/" title="算法热题(二)"><img src="/img/default_img.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="算法热题(二)"/></a><div class="content"><a class="title" href="/2025/04/11/LeetCode%E7%AE%97%E6%B3%95%E9%A2%98%EF%BC%88%E4%BA%8C%EF%BC%89/" title="算法热题(二)">算法热题(二)</a><time datetime="2025-04-11T09:24:23.000Z" title="发表于 2025-04-11 17:24:23">2025-04-11</time></div></div></div></div><div class="card-widget card-categories"><div class="item-headline">
<i class="fas fa-folder-open"></i>
<span>分类</span>
</div>
<ul class="card-category-list" id="aside-cat-list">
<li class="card-category-list-item "><a class="card-category-list-link" href="/categories/AI/"><span class="card-category-list-name">AI</span><span class="card-category-list-count">1</span></a></li><li class="card-category-list-item "><a class="card-category-list-link" href="/categories/%E6%8A%80%E6%9C%AF/"><span class="card-category-list-name">技术</span><span class="card-category-list-count">16</span></a></li><li class="card-category-list-item "><a class="card-category-list-link" href="/categories/%E6%96%B9%E6%A1%88/"><span class="card-category-list-name">方案</span><span class="card-category-list-count">1</span></a></li><li class="card-category-list-item "><a class="card-category-list-link" href="/categories/%E7%AE%97%E6%B3%95/"><span class="card-category-list-name">算法</span><span class="card-category-list-count">4</span></a></li>
</ul></div><div class="card-widget card-tags"><div class="item-headline"><i class="fas fa-tags"></i><span>标签</span></div><div class="card-tag-cloud"><a href="/tags/%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B/" style="font-size: 1.1em; color: #999">异步编程</a> <a href="/tags/FastAPI/" style="font-size: 1.1em; color: #999">FastAPI</a> <a href="/tags/%E4%B8%9A%E5%8A%A1/" style="font-size: 1.1em; color: #999">业务</a> <a href="/tags/%E7%AE%97%E6%B3%95%E5%9F%BA%E7%A1%80/" style="font-size: 1.3em; color: #99a1ac">算法基础</a> <a href="/tags/Nacos/" style="font-size: 1.1em; color: #999">Nacos</a> <a href="/tags/python/" style="font-size: 1.1em; color: #999">Python</a> <a href="/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/" style="font-size: 1.5em; color: #99a9bf">设计模式</a> <a href="/tags/SpringBoot/" style="font-size: 1.1em; color: #999">SpringBoot</a> <a href="/tags/SSE/" style="font-size: 1.1em; color: #999">SSE</a> <a href="/tags/%E7%AE%97%E6%B3%95%E9%A2%98/" style="font-size: 1.3em; color: #99a1ac">算法题</a></div></div><div class="card-widget card-archives">
<div class="item-headline">
<i class="fas fa-archive"></i>
<span>归档</span>
<a class="card-more-btn" href="/archives/"
title="查看更多">
<i class="fas fa-angle-right"></i>
</a>
</div>
<ul class="card-archive-list">
<li class="card-archive-list-item">
<a class="card-archive-list-link" href="/archives/2026/02/">
<span class="card-archive-list-date">
二月 2026
</span>
<span class="card-archive-list-count">1</span>
</a>
</li>
<li class="card-archive-list-item">
<a class="card-archive-list-link" href="/archives/2025/06/">
<span class="card-archive-list-date">
六月 2025
</span>
<span class="card-archive-list-count">2</span>
</a>
</li>
<li class="card-archive-list-item">
<a class="card-archive-list-link" href="/archives/2025/05/">
<span class="card-archive-list-date">
五月 2025
</span>
<span class="card-archive-list-count">1</span>
</a>
</li>
<li class="card-archive-list-item">
<a class="card-archive-list-link" href="/archives/2025/04/">
<span class="card-archive-list-date">
四月 2025
</span>
<span class="card-archive-list-count">1</span>
</a>
</li>
<li class="card-archive-list-item">
<a class="card-archive-list-link" href="/archives/2025/03/">
<span class="card-archive-list-date">
三月 2025
</span>
<span class="card-archive-list-count">1</span>
</a>
</li>
<li class="card-archive-list-item">
<a class="card-archive-list-link" href="/archives/2025/02/">
<span class="card-archive-list-date">
二月 2025
</span>
<span class="card-archive-list-count">1</span>
</a>
</li>
<li class="card-archive-list-item">
<a class="card-archive-list-link" href="/archives/2025/01/">
<span class="card-archive-list-date">
一月 2025
</span>
<span class="card-archive-list-count">1</span>
</a>
</li>
<li class="card-archive-list-item">
<a class="card-archive-list-link" href="/archives/2024/12/">
<span class="card-archive-list-date">
十二月 2024
</span>
<span class="card-archive-list-count">1</span>
</a>
</li>
</ul>
</div><div class="card-widget card-webinfo"><div class="item-headline"><i class="fas fa-chart-line"></i><span>网站信息</span></div><div class="webinfo"><div class="webinfo-item"><div class="item-name">文章数目 :</div><div class="item-count">22</div></div><div class="webinfo-item"><div class="item-name">运行时间 :</div><div class="item-count" id="runtimeshow" data-publishDate="2022-07-28T01:03:00.000Z"><i class="fa-solid fa-spinner fa-spin"></i></div></div><div class="webinfo-item"><div class="item-name">本站总字数 :</div><div class="item-count">77.2k</div></div><div class="webinfo-item"><div class="item-name">本站访客数 :</div><div class="item-count" id="busuanzi_value_site_uv"><i class="fa-solid fa-spinner fa-spin"></i></div></div><div class="webinfo-item"><div class="item-name">本站总浏览量 :</div><div class="item-count" id="busuanzi_value_site_pv"><i class="fa-solid fa-spinner fa-spin"></i></div></div><div class="webinfo-item"><div class="item-name">最后更新时间 :</div><div class="item-count" id="last-push-date" data-lastPushDate="2026-03-19T14:55:03.720Z"><i class="fa-solid fa-spinner fa-spin"></i></div></div></div></div></div></div></main><footer id="footer"><div class="footer-other"><div class="footer-copyright"><span class="copyright">© 2022 - 2026 By Lavigne-yang</span></div><div class="footer_custom_text">Hi, welcome to my <a target="_blank" rel="noopener" href="https://Lavigne-yang.github.io">blog</a>!</div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="translateLink" type="button" title="简繁转换">繁</button><button id="darkmode" type="button" title="日间和夜间模式切换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside-config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="/js/tw_cn.js"></script><div class="js-pjax"><script>window.typedJSFn = {
init: str => {
window.typed = new Typed('#subtitle', Object.assign({
strings: str,
startDelay: 300,
typeSpeed: 150,
loop: true,
backSpeed: 50,
}, null))
},
run: subtitleType => {
if (true) {
if (typeof Typed === 'function') {
subtitleType()
} else {
btf.getScript('https://cdn.jsdelivr.net/npm/typed.js/dist/typed.umd.min.js').then(subtitleType)
}
} else {
subtitleType()
}
},
processSubtitle: (content, extraContents = []) => {
if (true) {
const sub = ["不管风吹浪打,胜似闲庭信步"].slice()
if (extraContents.length > 0) {
sub.unshift(...extraContents)
}
if (typeof content === 'string') {
sub.unshift(content)
} else if (Array.isArray(content)) {
sub.unshift(...content)
}
sub.length > 0 && typedJSFn.init(sub)
} else {
document.getElementById('subtitle').textContent = typeof content === 'string' ? content :
(Array.isArray(content) && content.length > 0 ? content[0] : '')
}
}
}
btf.addGlobalFn('pjaxSendOnce', () => { typed.destroy() }, 'typedDestroy')
</script><script>function subtitleType () {
typedJSFn.processSubtitle(["不管风吹浪打,胜似闲庭信步"])
}
typedJSFn.run(subtitleType)</script></div><script defer="defer" id="fluttering_ribbon" mobile="true" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/canvas-fluttering-ribbon.min.js"></script><script async data-pjax src="https://cdn.bootcdn.net/ajax/libs/busuanzi/2.3.0/bsz.pure.mini.js"></script></div></body></html>