@llryiop/avatar-boot-cli 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/exam-question-generate-api.md +163 -0
- package/package.json +1 -1
- package/src/prompts.js +3 -3
- package/src/transform.js +1 -1
- package/templates/.claude/skills/avatar-boot-starter-feign/README.md +243 -0
- package/templates/.claude/skills/avatar-boot-starter-feign/SKILL.md +47 -219
- package/templates/.claude/skills/avatar-boot-starter-feign/references//345/212/237/350/203/275/350/257/246/350/247/243.md +65 -0
- package/templates/.claude/skills/avatar-boot-starter-feign/references//345/277/253/351/200/237/346/216/245/345/205/245/346/214/207/345/215/227.md +75 -0
- package/templates/.claude/skills/avatar-boot-starter-feign/references//351/205/215/347/275/256/345/217/202/350/200/203.md +70 -0
- package/templates/.claude/skills/avatar-boot-starter-job/README.md +437 -0
- package/templates/.claude/skills/avatar-boot-starter-job/SKILL.md +35 -414
- package/templates/.claude/skills/avatar-boot-starter-job/references//345/270/270/350/247/201/351/227/256/351/242/230.md +55 -0
- package/templates/.claude/skills/avatar-boot-starter-job/references//345/277/253/351/200/237/346/216/245/345/205/245/344/270/216/351/205/215/347/275/256.md +124 -0
- package/templates/.claude/skills/avatar-boot-starter-job/references//347/233/221/346/216/247/346/214/207/346/240/207.md +72 -0
- package/templates/.claude/skills/avatar-boot-starter-kafka/README.md +580 -0
- package/templates/.claude/skills/avatar-boot-starter-kafka/SKILL.md +36 -560
- package/templates/.claude/skills/avatar-boot-starter-kafka/references//346/234/200/344/275/263/345/256/236/350/267/265.md +43 -0
- package/templates/.claude/skills/avatar-boot-starter-kafka/references//346/240/270/345/277/203/345/212/237/350/203/275.md +117 -0
- package/templates/.claude/skills/avatar-boot-starter-kafka/references//351/205/215/347/275/256/345/217/202/350/200/203.md +54 -0
- package/templates/.claude/skills/avatar-boot-starter-mysql/README.md +572 -0
- package/templates/.claude/skills/avatar-boot-starter-mysql/SKILL.md +40 -550
- package/templates/.claude/skills/avatar-boot-starter-mysql/references//345/256/236/344/275/223/344/270/216/345/212/237/350/203/275.md +96 -0
- package/templates/.claude/skills/avatar-boot-starter-mysql/references//345/277/253/351/200/237/346/216/245/345/205/245/344/270/216/346/225/260/346/215/256/346/272/220.md +91 -0
- package/templates/.claude/skills/avatar-boot-starter-mysql/references//351/253/230/347/272/247/347/211/271/346/200/247/344/270/216/351/205/215/347/275/256.md +59 -0
- package/templates/.claude/skills/avatar-boot-starter-nacos/README.md +901 -0
- package/templates/.claude/skills/avatar-boot-starter-nacos/SKILL.md +40 -879
- package/templates/.claude/skills/avatar-boot-starter-nacos/references//345/212/237/350/203/275/344/275/277/347/224/250.md +134 -0
- package/templates/.claude/skills/avatar-boot-starter-nacos/references//345/277/253/351/200/237/346/216/245/345/205/245/344/270/216/351/205/215/347/275/256.md +96 -0
- package/templates/.claude/skills/avatar-boot-starter-nacos/references//346/225/205/351/232/234/346/216/222/346/237/245.md +64 -0
- package/templates/.claude/skills/avatar-boot-starter-oss/README.md +594 -0
- package/templates/.claude/skills/avatar-boot-starter-oss/SKILL.md +52 -570
- package/templates/.claude/skills/avatar-boot-starter-oss/references//345/277/253/351/200/237/346/216/245/345/205/245/344/270/216/351/205/215/347/275/256.md +77 -0
- package/templates/.claude/skills/avatar-boot-starter-oss/references//346/240/270/345/277/203/345/212/237/350/203/275.md +94 -0
- package/templates/.claude/skills/avatar-boot-starter-oss/references//350/247/204/350/214/203/344/270/216/346/263/250/346/204/217/344/272/213/351/241/271.md +61 -0
- package/templates/.claude/skills/avatar-boot-starter-redis/README.md +586 -0
- package/templates/.claude/skills/avatar-boot-starter-redis/SKILL.md +42 -566
- package/templates/.claude/skills/avatar-boot-starter-redis/references//345/277/253/351/200/237/346/216/245/345/205/245/344/270/216/351/205/215/347/275/256.md +78 -0
- package/templates/.claude/skills/avatar-boot-starter-redis/references//346/225/260/346/215/256/346/223/215/344/275/234.md +111 -0
- package/templates/.claude/skills/avatar-boot-starter-redis/references//351/253/230/347/272/247/345/212/237/350/203/275.md +90 -0
- package/templates/.claude/skills/avatar-boot-starter-rocketmq/README.md +662 -0
- package/templates/.claude/skills/avatar-boot-starter-rocketmq/SKILL.md +48 -640
- package/templates/.claude/skills/avatar-boot-starter-rocketmq/references//346/240/270/345/277/203/345/212/237/350/203/275.md +101 -0
- package/templates/.claude/skills/avatar-boot-starter-rocketmq/references//351/205/215/347/275/256/344/270/216/346/263/250/346/204/217/344/272/213/351/241/271.md +44 -0
- package/templates/.claude/skills/avatar-boot-starter-rocketmq/references//351/253/230/347/272/247/347/211/271/346/200/247.md +71 -0
- package/templates/.claude/skills/avatar-boot-starter-web/README.md +1007 -0
- package/templates/.claude/skills/avatar-boot-starter-web/SKILL.md +150 -1003
- package/templates/.claude/skills/avatar-boot-starter-web/references//345/212/237/350/203/275-LogInfo/346/263/250/350/247/243.md +75 -0
- package/templates/.claude/skills/avatar-boot-starter-web/references//345/212/237/350/203/275-/345/205/250/345/261/200/345/274/202/345/270/270/345/244/204/347/220/206.md +90 -0
- package/templates/.claude/skills/avatar-boot-starter-web/references//345/212/237/350/203/275-/346/214/207/346/240/207/347/233/221/346/216/247.md +74 -0
- package/templates/.claude/skills/avatar-boot-starter-web/references//345/212/237/350/203/275-/346/227/245/345/277/227/344/275/223/347/263/273.md +73 -0
- package/templates/.claude/skills/avatar-boot-starter-web/references//345/212/237/350/203/275-/350/257/267/346/261/202/344/270/212/344/270/213/346/226/207.md +77 -0
- package/templates/.claude/skills/avatar-boot-starter-web/references//345/277/253/351/200/237/346/216/245/345/205/245/346/214/207/345/215/227.md +52 -0
- package/templates/.claude/skills/avatar-boot-starter-web/references//346/263/250/346/204/217/344/272/213/351/241/271.md +68 -0
- package/templates/.claude/skills/avatar-boot-starter-web/references//350/207/252/345/256/232/344/271/211/346/211/251/345/261/225/346/214/207/345/215/227.md +107 -0
- package/templates/.claude/skills/avatar-boot-starter-web/references//351/205/215/347/275/256/345/217/202/350/200/203.md +107 -0
- package/templates/.claude/skills/crud-generator/SKILL.md +133 -64
- package/templates/.claude/skills/database-design/README.md +207 -0
- package/templates/.claude/skills/database-design/SKILL.md +469 -82
- package/templates/.claude/skills/database-design/references//345/221/275/345/220/215/350/247/204/350/214/203.md +232 -0
- package/templates/.claude/skills/database-design/references//345/255/227/346/256/265/347/261/273/345/236/213/350/247/204/350/214/203.md +400 -0
- package/templates/.claude/skills/database-design/references//347/264/242/345/274/225/350/247/204/350/214/203.md +506 -0
- package/templates/README.md +65 -100
- package/templates/avatar-scaffold-api/pom.xml +0 -5
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/api/LoginFeignClient.java +2 -0
- package/templates/avatar-scaffold-api/src/main/java/com/iflytek/avatar/login/exception/LoginErrorCode.java +25 -0
- package/templates/avatar-scaffold-service/pom.xml +25 -87
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/feign/DemoFeign.java +4 -1
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/repository/UserLoginRepository.java +10 -0
- package/templates/avatar-scaffold-service/src/main/java/com/iflytek/avatar/login/repository/mapper/UserLoginMapper.java +4 -1
- package/templates/avatar-scaffold-service/src/main/resources/application-dev.yaml +3 -5
- package/templates/avatar-scaffold-service/src/main/resources/application-local.yaml +21 -21
- package/templates/pom.xml +9 -18
|
@@ -1,1007 +1,154 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: avatar-boot-starter-web
|
|
3
|
-
description:
|
|
3
|
+
description: Avatar Boot Web 模块使用指南与代码接入助手。当用户询问 avatar-boot-starter-web 的功能使用、配置方式、异常处理、日志配置、TraceId 传递、@LogInfo 注解、指标监控,或需要接入 Web 模块时触发。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Avatar Boot Starter Web
|
|
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
|
-
return userInfo;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
**日志输出:**
|
|
161
|
-
```
|
|
162
|
-
[UserService.getUserById] Status: SUCCESS, Time: 156ms
|
|
163
|
-
→ Request: [123]
|
|
164
|
-
→ Response: {"id":123,"name":"John Doe"}
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
**慢方法警告:**
|
|
168
|
-
```
|
|
169
|
-
[UserService.getUserById] Status: SUCCESS, Time: 2345ms (⚠️ threshold: 2000ms)
|
|
170
|
-
→ Request: [123]
|
|
171
|
-
→ Response: {"id":123,"name":"John Doe"}
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
### 4. 全局异常处理
|
|
175
|
-
|
|
176
|
-
**功能说明:**
|
|
177
|
-
- 捕获所有异常并返回标准化的 `Result<?>` 响应
|
|
178
|
-
- 处理业务异常、参数校验错误和系统错误
|
|
179
|
-
- 记录异常及请求上下文(URI、方法)
|
|
180
|
-
- 返回适当的 HTTP 状态码
|
|
181
|
-
|
|
182
|
-
**支持的异常类型:**
|
|
183
|
-
- `BusinessException` - 业务逻辑错误(HTTP 200 带错误码)
|
|
184
|
-
- `MethodArgumentNotValidException` - @RequestBody 校验(HTTP 400)
|
|
185
|
-
- `BindException` - @ModelAttribute 校验(HTTP 400)
|
|
186
|
-
- `ConstraintViolationException` - @RequestParam 校验(HTTP 400)
|
|
187
|
-
- `RuntimeException` - 运行时错误(HTTP 500)
|
|
188
|
-
- `Exception` - 所有其他异常(HTTP 500)
|
|
189
|
-
|
|
190
|
-
**使用示例:**
|
|
191
|
-
```java
|
|
192
|
-
import com.iflytek.avatar.boot.exception.BusinessException;
|
|
193
|
-
import com.iflytek.avatar.boot.entity.response.ResultCode;
|
|
194
|
-
|
|
195
|
-
@Service
|
|
196
|
-
public class UserService {
|
|
197
|
-
|
|
198
|
-
public void updateUser(Long userId) {
|
|
199
|
-
if (userId == null) {
|
|
200
|
-
throw new BusinessException(ResultCode.PARAM_ERROR, "用户ID不能为空");
|
|
201
|
-
}
|
|
202
|
-
// 业务逻辑
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
**响应格式:**
|
|
208
|
-
```json
|
|
209
|
-
{
|
|
210
|
-
"code": 400,
|
|
211
|
-
"message": "用户ID不能为空",
|
|
212
|
-
"data": null,
|
|
213
|
-
"success": false
|
|
214
|
-
}
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
### 5. 指标集成
|
|
218
|
-
|
|
219
|
-
**功能说明:**
|
|
220
|
-
- 记录方法调用次数和执行时间
|
|
221
|
-
- 使用 Micrometer 进行指标收集
|
|
222
|
-
- 缓存指标实例以避免重复注册
|
|
223
|
-
- 支持成功/失败状态追踪
|
|
224
|
-
|
|
225
|
-
**记录的指标:**
|
|
226
|
-
- `method.invocation.count` - 计数器,标签:class、method、status
|
|
227
|
-
- `method.execution.time` - 计时器,标签:class、method、status
|
|
228
|
-
|
|
229
|
-
**使用方式:**
|
|
230
|
-
使用 `@LogInfo(metrics = true)` 时会自动记录指标。
|
|
231
|
-
|
|
232
|
-
**手动记录:**
|
|
233
|
-
```java
|
|
234
|
-
@Autowired
|
|
235
|
-
private MetricsRecorder metricsRecorder;
|
|
236
|
-
|
|
237
|
-
public void someMethod() {
|
|
238
|
-
long startTime = System.currentTimeMillis();
|
|
239
|
-
try {
|
|
240
|
-
// 业务逻辑
|
|
241
|
-
long costTime = System.currentTimeMillis() - startTime;
|
|
242
|
-
metricsRecorder.recordMethodMetrics("MyClass", "someMethod", costTime, null);
|
|
243
|
-
} catch (Exception e) {
|
|
244
|
-
long costTime = System.currentTimeMillis() - startTime;
|
|
245
|
-
metricsRecorder.recordMethodMetrics("MyClass", "someMethod", costTime, e);
|
|
246
|
-
throw e;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
### 6. CORS 支持
|
|
252
|
-
|
|
253
|
-
**功能说明:**
|
|
254
|
-
- 提供可配置的跨域资源共享
|
|
255
|
-
- 出于安全考虑默认禁用
|
|
256
|
-
- 支持自定义源、方法、请求头和凭证
|
|
257
|
-
|
|
258
|
-
**配置示例:**
|
|
259
|
-
```yaml
|
|
260
|
-
avatar:
|
|
261
|
-
web:
|
|
262
|
-
cors-enabled: true
|
|
263
|
-
cors:
|
|
264
|
-
allowed-origins:
|
|
265
|
-
- "https://example.com"
|
|
266
|
-
- "https://app.example.com"
|
|
267
|
-
allowed-methods:
|
|
268
|
-
- GET
|
|
269
|
-
- POST
|
|
270
|
-
- PUT
|
|
271
|
-
- DELETE
|
|
272
|
-
allowed-headers:
|
|
273
|
-
- "*"
|
|
274
|
-
exposed-headers:
|
|
275
|
-
- X-Trace-Id
|
|
276
|
-
allow-credentials: true
|
|
277
|
-
max-age: 3600
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
### 7. TraceID 异步支持与 Micrometer 集成
|
|
281
|
-
|
|
282
|
-
**版本要求:** Avatar Boot 1.0.0-SNAPSHOT+
|
|
283
|
-
|
|
284
|
-
**功能说明:**
|
|
285
|
-
- 使用 TransmittableThreadLocal 自动传播 TraceID 到异步线程
|
|
286
|
-
- 支持 @Async、CompletableFuture、自定义线程池
|
|
287
|
-
- 可插拔的 TraceID 生成器(UUID、Snowflake、自定义)
|
|
288
|
-
- 可选的 Micrometer Tracing 集成(支持 Zipkin、Jaeger)
|
|
289
|
-
- 向后兼容,无需修改现有代码
|
|
290
|
-
|
|
291
|
-
**核心改进:**
|
|
292
|
-
|
|
293
|
-
#### 7.1 异步场景自动支持
|
|
294
|
-
|
|
295
|
-
**问题:** 之前使用普通 ThreadLocal,无法在异步线程中传播 TraceID
|
|
296
|
-
|
|
297
|
-
**解决方案:**
|
|
298
|
-
- 使用阿里巴巴的 TransmittableThreadLocal (TTL)
|
|
299
|
-
- 自动配置 TaskDecorator 装饰异步任务
|
|
300
|
-
- 支持 @Async、CompletableFuture、自定义线程池
|
|
301
|
-
|
|
302
|
-
**使用示例:**
|
|
303
|
-
|
|
304
|
-
```java
|
|
305
|
-
@Service
|
|
306
|
-
public class UserService {
|
|
307
|
-
|
|
308
|
-
@Async
|
|
309
|
-
public CompletableFuture<User> getUserAsync(String userId) {
|
|
310
|
-
// TraceID 自动传播到异步线程
|
|
311
|
-
String traceId = ContextManager.get().getTraceId();
|
|
312
|
-
log.info("Async thread TraceID: {}", traceId);
|
|
313
|
-
|
|
314
|
-
User user = userRepository.findById(userId);
|
|
315
|
-
return CompletableFuture.completedFuture(user);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
**日志输出:**
|
|
321
|
-
```
|
|
322
|
-
[main] [abc123] Request started: GET /users/1
|
|
323
|
-
[avatar-async-1] [abc123] Async thread TraceID: abc123
|
|
324
|
-
[main] [abc123] Request completed: GET /users/1 - 150ms
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
#### 7.2 可插拔的 TraceID 生成器
|
|
328
|
-
|
|
329
|
-
**默认实现:** 使用 UUID(去除连字符)
|
|
330
|
-
|
|
331
|
-
**自定义实现:**
|
|
332
|
-
|
|
333
|
-
```java
|
|
334
|
-
@Component
|
|
335
|
-
public class SnowflakeTraceIdGenerator implements TraceIdGenerator {
|
|
336
|
-
|
|
337
|
-
private final Snowflake snowflake = IdUtil.getSnowflake(1, 1);
|
|
338
|
-
|
|
339
|
-
@Override
|
|
340
|
-
public String generate() {
|
|
341
|
-
return String.valueOf(snowflake.nextId());
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
#### 7.3 Micrometer Tracing 集成(可选)
|
|
347
|
-
|
|
348
|
-
**启用方式:**
|
|
349
|
-
|
|
350
|
-
```yaml
|
|
351
|
-
avatar:
|
|
352
|
-
web:
|
|
353
|
-
tracing:
|
|
354
|
-
micrometer-enabled: true
|
|
355
|
-
|
|
356
|
-
management:
|
|
357
|
-
tracing:
|
|
358
|
-
enabled: true
|
|
359
|
-
sampling:
|
|
360
|
-
probability: 1.0
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
**收益:**
|
|
364
|
-
- 与 Spring Cloud 生态无缝集成
|
|
365
|
-
- 支持 Zipkin、Jaeger 等分布式追踪系统
|
|
366
|
-
- 自动传播 W3C Trace Context 和 B3 格式
|
|
367
|
-
|
|
368
|
-
**异步配置:**
|
|
369
|
-
|
|
370
|
-
```yaml
|
|
371
|
-
avatar:
|
|
372
|
-
web:
|
|
373
|
-
async:
|
|
374
|
-
enabled: true # 是否启用异步支持(默认:true)
|
|
375
|
-
core-pool-size: 10 # 核心线程数
|
|
376
|
-
max-pool-size: 50 # 最大线程数
|
|
377
|
-
queue-capacity: 200 # 队列容量
|
|
378
|
-
thread-name-prefix: avatar-async-
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
**追踪配置:**
|
|
382
|
-
|
|
383
|
-
```yaml
|
|
384
|
-
avatar:
|
|
385
|
-
web:
|
|
386
|
-
tracing:
|
|
387
|
-
micrometer-enabled: false # 是否启用 Micrometer 集成(默认:false)
|
|
388
|
-
generator-type: uuid # TraceID 生成策略(uuid, snowflake, custom)
|
|
389
|
-
```
|
|
390
|
-
|
|
391
|
-
**性能影响:**
|
|
392
|
-
- 内存开销:每个异步任务额外复制一份上下文(约 1KB)
|
|
393
|
-
- CPU 开销:上下文复制和恢复(< 1ms)
|
|
394
|
-
- 总体影响:< 5%(压测验证)
|
|
395
|
-
|
|
396
|
-
**依赖版本:**
|
|
397
|
-
- TransmittableThreadLocal: 2.14.5
|
|
398
|
-
- Micrometer Tracing: 1.4.3(可选)
|
|
399
|
-
|
|
400
|
-
## 配置指南
|
|
401
|
-
|
|
402
|
-
### 基础配置(最小化)
|
|
403
|
-
|
|
404
|
-
```yaml
|
|
405
|
-
spring:
|
|
406
|
-
application:
|
|
407
|
-
name: my-app
|
|
408
|
-
|
|
409
|
-
# 所有功能默认启用,无需额外配置
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
### 高级配置(所有选项)
|
|
413
|
-
|
|
414
|
-
```yaml
|
|
415
|
-
avatar:
|
|
416
|
-
web:
|
|
417
|
-
# 功能开关
|
|
418
|
-
interceptor-enabled: true # 启用请求拦截器(默认:true)
|
|
419
|
-
exception-handler-enabled: true # 启用全局异常处理器(默认:true)
|
|
420
|
-
cors-enabled: false # 启用 CORS(默认:false)
|
|
421
|
-
|
|
422
|
-
# 拦截器配置
|
|
423
|
-
interceptor:
|
|
424
|
-
trace-id-header: X-Trace-Id # TraceId 请求头名称(默认:X-Trace-Id)
|
|
425
|
-
include-paths: # 拦截路径(默认:/**)
|
|
426
|
-
- /**
|
|
427
|
-
exclude-paths: # 排除路径
|
|
428
|
-
- /error
|
|
429
|
-
- /actuator/**
|
|
430
|
-
- /favicon.ico
|
|
431
|
-
- /webjars/**
|
|
432
|
-
- /swagger-ui/**
|
|
433
|
-
- /v3/api-docs/**
|
|
434
|
-
|
|
435
|
-
# 日志配置
|
|
436
|
-
log:
|
|
437
|
-
request-enabled: true # 记录请求开始(默认:true)
|
|
438
|
-
response-enabled: true # 记录请求完成(默认:true)
|
|
439
|
-
slow-request-threshold: 3000 # 慢请求阈值(毫秒)(默认:3000)
|
|
440
|
-
|
|
441
|
-
# 异步配置(1.0.0-SNAPSHOT+)
|
|
442
|
-
async:
|
|
443
|
-
enabled: true # 启用异步支持(默认:true)
|
|
444
|
-
core-pool-size: 10 # 核心线程数(默认:10)
|
|
445
|
-
max-pool-size: 50 # 最大线程数(默认:50)
|
|
446
|
-
queue-capacity: 200 # 队列容量(默认:200)
|
|
447
|
-
thread-name-prefix: avatar-async- # 线程名前缀(默认:avatar-async-)
|
|
448
|
-
|
|
449
|
-
# 追踪配置(1.0.0-SNAPSHOT+)
|
|
450
|
-
tracing:
|
|
451
|
-
micrometer-enabled: false # 启用 Micrometer 集成(默认:false)
|
|
452
|
-
generator-type: uuid # TraceID 生成策略(uuid, snowflake, custom)
|
|
453
|
-
|
|
454
|
-
# CORS 配置(仅当 cors-enabled: true 时生效)
|
|
455
|
-
cors:
|
|
456
|
-
allowed-origins:
|
|
457
|
-
- "*"
|
|
458
|
-
allowed-methods:
|
|
459
|
-
- GET
|
|
460
|
-
- POST
|
|
461
|
-
- PUT
|
|
462
|
-
- DELETE
|
|
463
|
-
- OPTIONS
|
|
464
|
-
allowed-headers:
|
|
465
|
-
- "*"
|
|
466
|
-
exposed-headers:
|
|
467
|
-
- X-Trace-Id
|
|
468
|
-
allow-credentials: true
|
|
469
|
-
max-age: 3600
|
|
470
|
-
|
|
471
|
-
# 日志配置
|
|
472
|
-
logging:
|
|
473
|
-
level:
|
|
474
|
-
root: INFO
|
|
475
|
-
com.iflytek.avatar.boot: DEBUG
|
|
476
|
-
file:
|
|
477
|
-
path: logs
|
|
478
|
-
```
|
|
479
|
-
|
|
480
|
-
### 环境特定配置
|
|
481
|
-
|
|
482
|
-
**开发环境(dev):**
|
|
483
|
-
```yaml
|
|
484
|
-
spring:
|
|
485
|
-
config:
|
|
486
|
-
activate:
|
|
487
|
-
on-profile: dev
|
|
488
|
-
|
|
489
|
-
avatar:
|
|
490
|
-
web:
|
|
491
|
-
log:
|
|
492
|
-
slow-request-threshold: 5000 # 开发环境放宽阈值
|
|
493
|
-
|
|
494
|
-
logging:
|
|
495
|
-
level:
|
|
496
|
-
root: INFO
|
|
497
|
-
com.iflytek.avatar.boot: DEBUG
|
|
498
|
-
```
|
|
499
|
-
|
|
500
|
-
**生产环境(prod):**
|
|
501
|
-
```yaml
|
|
502
|
-
spring:
|
|
503
|
-
config:
|
|
504
|
-
activate:
|
|
505
|
-
on-profile: prod
|
|
506
|
-
|
|
507
|
-
avatar:
|
|
508
|
-
web:
|
|
509
|
-
cors-enabled: false # 生产环境禁用 CORS
|
|
510
|
-
log:
|
|
511
|
-
slow-request-threshold: 2000 # 生产环境更严格的阈值
|
|
512
|
-
|
|
513
|
-
logging:
|
|
514
|
-
level:
|
|
515
|
-
root: INFO
|
|
516
|
-
com.iflytek.avatar.boot: INFO
|
|
517
|
-
file:
|
|
518
|
-
path: /var/log/app
|
|
519
|
-
```
|
|
520
|
-
|
|
521
|
-
## 常见使用场景
|
|
522
|
-
|
|
523
|
-
### 场景 1:API 网关集成
|
|
524
|
-
|
|
525
|
-
在 API 网关(Kong、Nginx)后构建服务时:
|
|
526
|
-
|
|
527
|
-
```yaml
|
|
528
|
-
avatar:
|
|
529
|
-
web:
|
|
530
|
-
interceptor:
|
|
531
|
-
trace-id-header: X-Request-Id # 匹配网关的请求头名称
|
|
532
|
-
exclude-paths:
|
|
533
|
-
- /health
|
|
534
|
-
- /metrics
|
|
535
|
-
```
|
|
536
|
-
|
|
537
|
-
### 场景 2:微服务分布式追踪
|
|
538
|
-
|
|
539
|
-
```java
|
|
540
|
-
@Service
|
|
541
|
-
public class OrderService {
|
|
542
|
-
|
|
543
|
-
@Autowired
|
|
544
|
-
private RestTemplate restTemplate;
|
|
545
|
-
|
|
546
|
-
public void createOrder(OrderRequest request) {
|
|
547
|
-
// TraceId 自动可用
|
|
548
|
-
AvatarContext context = ContextManager.get();
|
|
549
|
-
String traceId = context.getTraceId();
|
|
550
|
-
|
|
551
|
-
// 将 TraceId 传播到下游服务
|
|
552
|
-
HttpHeaders headers = new HttpHeaders();
|
|
553
|
-
headers.set("X-Trace-Id", traceId);
|
|
554
|
-
|
|
555
|
-
HttpEntity<OrderRequest> entity = new HttpEntity<>(request, headers);
|
|
556
|
-
restTemplate.postForObject("http://inventory-service/api/reserve", entity, Void.class);
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
```
|
|
560
|
-
|
|
561
|
-
### 场景 3:性能监控
|
|
562
|
-
|
|
563
|
-
```java
|
|
564
|
-
@RestController
|
|
565
|
-
@RequestMapping("/api/reports")
|
|
566
|
-
public class ReportController {
|
|
567
|
-
|
|
568
|
-
@LogInfo(request = true, response = false, metrics = true, costTime = 5000)
|
|
569
|
-
@GetMapping("/sales")
|
|
570
|
-
public Result<SalesReport> generateSalesReport(@RequestParam String startDate,
|
|
571
|
-
@RequestParam String endDate) {
|
|
572
|
-
// 重计算
|
|
573
|
-
SalesReport report = reportService.generateReport(startDate, endDate);
|
|
574
|
-
return Result.success(report);
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
```
|
|
578
|
-
|
|
579
|
-
### 场景 4:自定义异常处理
|
|
580
|
-
|
|
581
|
-
```java
|
|
582
|
-
@Component
|
|
583
|
-
public class CustomExceptionHandler extends GlobalExceptionHandler {
|
|
584
|
-
|
|
585
|
-
@ExceptionHandler(AuthenticationException.class)
|
|
586
|
-
@ResponseStatus(HttpStatus.UNAUTHORIZED)
|
|
587
|
-
public Result<?> handleAuthenticationException(AuthenticationException e) {
|
|
588
|
-
log.error("Authentication failed: {}", e.getMessage());
|
|
589
|
-
return Result.fail(401, "认证失败,请重新登录");
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
```
|
|
593
|
-
|
|
594
|
-
### 场景 5:@Async 异步方法(1.0.0-SNAPSHOT+)
|
|
595
|
-
|
|
596
|
-
**自动支持 TraceID 传播**:
|
|
597
|
-
|
|
598
|
-
```java
|
|
599
|
-
@Service
|
|
600
|
-
public class NotificationService {
|
|
601
|
-
|
|
602
|
-
@Async
|
|
603
|
-
public void sendNotification(String userId, String message) {
|
|
604
|
-
// TraceID 自动传播到异步线程
|
|
605
|
-
String traceId = ContextManager.get().getTraceId();
|
|
606
|
-
log.info("Sending notification with TraceID: {}", traceId);
|
|
607
|
-
// ... 发送通知
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
```
|
|
611
|
-
|
|
612
|
-
### 场景 6:CompletableFuture 并行处理(1.0.0-SNAPSHOT+)
|
|
613
|
-
|
|
614
|
-
**自动支持 TraceID 传播**:
|
|
615
|
-
|
|
616
|
-
```java
|
|
617
|
-
@Service
|
|
618
|
-
public class OrderService {
|
|
619
|
-
|
|
620
|
-
@Autowired
|
|
621
|
-
private Executor asyncExecutor;
|
|
622
|
-
|
|
623
|
-
public Order createOrder(OrderRequest request) {
|
|
624
|
-
String traceId = ContextManager.get().getTraceId();
|
|
625
|
-
|
|
626
|
-
CompletableFuture<Void> inventoryCheck = CompletableFuture.runAsync(() -> {
|
|
627
|
-
// TraceID 自动传播
|
|
628
|
-
log.info("Checking inventory with TraceID: {}", traceId);
|
|
629
|
-
inventoryService.checkStock(request.getProductId());
|
|
630
|
-
}, asyncExecutor);
|
|
631
|
-
|
|
632
|
-
CompletableFuture<Void> paymentProcess = CompletableFuture.runAsync(() -> {
|
|
633
|
-
// TraceID 自动传播
|
|
634
|
-
log.info("Processing payment with TraceID: {}", traceId);
|
|
635
|
-
paymentService.process(request.getPayment());
|
|
636
|
-
}, asyncExecutor);
|
|
637
|
-
|
|
638
|
-
CompletableFuture.allOf(inventoryCheck, paymentProcess).join();
|
|
639
|
-
|
|
640
|
-
return orderRepository.save(new Order(request));
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
```
|
|
644
|
-
|
|
645
|
-
### 场景 7:自定义线程池(1.0.0-SNAPSHOT+)
|
|
646
|
-
|
|
647
|
-
**需要使用 MdcTaskDecorator**:
|
|
648
|
-
|
|
649
|
-
```java
|
|
650
|
-
@Configuration
|
|
651
|
-
public class CustomThreadPoolConfig {
|
|
652
|
-
|
|
653
|
-
@Autowired
|
|
654
|
-
private MdcTaskDecorator mdcTaskDecorator;
|
|
655
|
-
|
|
656
|
-
@Bean
|
|
657
|
-
public ThreadPoolTaskExecutor customExecutor() {
|
|
658
|
-
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
|
659
|
-
executor.setCorePoolSize(5);
|
|
660
|
-
executor.setMaxPoolSize(10);
|
|
661
|
-
executor.setQueueCapacity(100);
|
|
662
|
-
executor.setThreadNamePrefix("custom-");
|
|
663
|
-
|
|
664
|
-
// 应用 MDC 任务装饰器以传播 TraceID
|
|
665
|
-
executor.setTaskDecorator(mdcTaskDecorator);
|
|
666
|
-
|
|
667
|
-
executor.initialize();
|
|
668
|
-
return executor;
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
```
|
|
672
|
-
|
|
673
|
-
## 故障排查
|
|
674
|
-
|
|
675
|
-
### 问题 1:日志中未显示 TraceId
|
|
676
|
-
|
|
677
|
-
**症状:**
|
|
678
|
-
- 日志中没有显示 TraceId(方括号内)
|
|
679
|
-
- JSON 日志中缺少 traceId 字段
|
|
680
|
-
|
|
681
|
-
**可能原因:**
|
|
682
|
-
1. 请求拦截器被禁用
|
|
683
|
-
2. 请求路径被排除
|
|
684
|
-
3. Logback 配置不正确
|
|
685
|
-
|
|
686
|
-
**解决方案:**
|
|
687
|
-
```yaml
|
|
688
|
-
# 1. 确保拦截器已启用
|
|
689
|
-
avatar:
|
|
690
|
-
web:
|
|
691
|
-
interceptor-enabled: true
|
|
692
|
-
|
|
693
|
-
# 2. 检查排除路径
|
|
694
|
-
avatar:
|
|
695
|
-
web:
|
|
696
|
-
interceptor:
|
|
697
|
-
exclude-paths:
|
|
698
|
-
- /actuator/** # 确保你的路径没有被排除
|
|
699
|
-
|
|
700
|
-
# 3. 验证 logback-spring.xml 包含 TraceId 模式
|
|
701
|
-
# 模式应包含:[%X{traceId}]
|
|
702
|
-
```
|
|
703
|
-
|
|
704
|
-
### 问题 2:CORS 错误
|
|
705
|
-
|
|
706
|
-
**症状:**
|
|
707
|
-
- 浏览器显示 CORS 策略错误
|
|
708
|
-
- 预检 OPTIONS 请求失败
|
|
709
|
-
|
|
710
|
-
**解决方案:**
|
|
711
|
-
```yaml
|
|
712
|
-
# 显式启用 CORS
|
|
713
|
-
avatar:
|
|
714
|
-
web:
|
|
715
|
-
cors-enabled: true
|
|
716
|
-
cors:
|
|
717
|
-
allowed-origins:
|
|
718
|
-
- "https://your-frontend-domain.com" # 使用凭证时不要用 "*"
|
|
719
|
-
allow-credentials: true
|
|
720
|
-
```
|
|
721
|
-
|
|
722
|
-
**重要提示:** 如果 `allow-credentials: true`,则不能使用 `allowed-origins: ["*"]`。必须指定确切的源。
|
|
723
|
-
|
|
724
|
-
### 问题 3:慢请求误报
|
|
725
|
-
|
|
726
|
-
**症状:**
|
|
727
|
-
- 许多请求被标记为 [SLOW],但实际上并不慢
|
|
728
|
-
- 阈值对你的使用场景来说太低
|
|
729
|
-
|
|
730
|
-
**解决方案:**
|
|
731
|
-
```yaml
|
|
732
|
-
# 根据环境调整阈值
|
|
733
|
-
avatar:
|
|
734
|
-
web:
|
|
735
|
-
log:
|
|
736
|
-
slow-request-threshold: 5000 # 增加到 5 秒
|
|
737
|
-
|
|
738
|
-
# 或禁用慢请求日志
|
|
739
|
-
avatar:
|
|
740
|
-
web:
|
|
741
|
-
log:
|
|
742
|
-
response-enabled: false
|
|
743
|
-
```
|
|
744
|
-
|
|
745
|
-
### 问题 4:ThreadLocal 内存泄漏
|
|
746
|
-
|
|
747
|
-
**症状:**
|
|
748
|
-
- 内存使用随时间增长
|
|
749
|
-
- 生产环境出现 OutOfMemoryError
|
|
750
|
-
|
|
751
|
-
**诊断:**
|
|
752
|
-
拦截器会在 `afterCompletion()` 中自动清理 ThreadLocal。如果出现内存泄漏:
|
|
753
|
-
|
|
754
|
-
1. 检查是否手动设置上下文但未清理:
|
|
755
|
-
```java
|
|
756
|
-
// ❌ 错误 - 手动设置但未清理
|
|
757
|
-
ContextManager.set(context);
|
|
758
|
-
// ... 业务逻辑
|
|
759
|
-
// 缺失:ContextManager.clear();
|
|
760
|
-
|
|
761
|
-
// ✅ 正确 - 让拦截器处理
|
|
762
|
-
AvatarContext context = ContextManager.get();
|
|
763
|
-
```
|
|
764
|
-
|
|
765
|
-
2. 验证拦截器已注册:
|
|
766
|
-
```yaml
|
|
767
|
-
avatar:
|
|
768
|
-
web:
|
|
769
|
-
interceptor-enabled: true # 必须为 true
|
|
770
|
-
```
|
|
771
|
-
|
|
772
|
-
### 问题 5:客户端 IP 显示为代理 IP
|
|
773
|
-
|
|
774
|
-
**症状:**
|
|
775
|
-
- `context.getClientIp()` 返回代理/负载均衡器 IP
|
|
776
|
-
- 未捕获真实客户端 IP
|
|
777
|
-
|
|
778
|
-
**解决方案:**
|
|
779
|
-
确保你的代理/负载均衡器设置了正确的请求头:
|
|
780
|
-
|
|
781
|
-
```nginx
|
|
782
|
-
# Nginx 配置
|
|
783
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
784
|
-
proxy_set_header X-Real-IP $remote_addr;
|
|
785
|
-
```
|
|
786
|
-
|
|
787
|
-
拦截器按以下顺序检查请求头:
|
|
788
|
-
1. `X-Forwarded-For`(如果有多个则取第一个 IP)
|
|
789
|
-
2. `X-Real-IP`
|
|
790
|
-
3. `Proxy-Client-IP`
|
|
791
|
-
4. `WL-Proxy-Client-IP`
|
|
792
|
-
5. `request.getRemoteAddr()`
|
|
793
|
-
|
|
794
|
-
### 问题 6:@LogInfo 不工作
|
|
795
|
-
|
|
796
|
-
**症状:**
|
|
797
|
-
- 使用 @LogInfo 注解的方法没有日志
|
|
798
|
-
- 指标未记录
|
|
799
|
-
|
|
800
|
-
**可能原因:**
|
|
801
|
-
1. AOP 未启用
|
|
802
|
-
2. 方法未通过 Spring 代理调用
|
|
803
|
-
3. LogInfoAspect 未注册
|
|
804
|
-
|
|
805
|
-
**解决方案:**
|
|
806
|
-
```java
|
|
807
|
-
// ❌ 错误 - 直接调用方法会绕过 AOP
|
|
808
|
-
@Service
|
|
809
|
-
public class UserService {
|
|
810
|
-
@LogInfo
|
|
811
|
-
public void method1() { }
|
|
812
|
-
|
|
813
|
-
public void method2() {
|
|
814
|
-
this.method1(); // 直接调用,AOP 不会拦截
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
// ✅ 正确 - 通过 Spring 代理调用
|
|
819
|
-
@Service
|
|
820
|
-
@RequiredArgsConstructor
|
|
821
|
-
public class UserService {
|
|
822
|
-
private final UserService self; // 注入自身
|
|
823
|
-
|
|
824
|
-
@LogInfo
|
|
825
|
-
public void method1() { }
|
|
826
|
-
|
|
827
|
-
public void method2() {
|
|
828
|
-
self.method1(); // 代理调用,AOP 生效
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
```
|
|
832
|
-
|
|
833
|
-
### 问题 7:异步线程中 TraceID 为 null(1.0.0-SNAPSHOT+)
|
|
834
|
-
|
|
835
|
-
**症状:**
|
|
836
|
-
- 异步方法中 `ContextManager.get().getTraceId()` 返回 null
|
|
837
|
-
- 异步线程的日志中没有 TraceID
|
|
838
|
-
|
|
839
|
-
**可能原因:**
|
|
840
|
-
1. 使用了自定义线程池但未应用 MdcTaskDecorator
|
|
841
|
-
2. 异步支持被禁用
|
|
842
|
-
3. 使用了不受管理的线程(如 new Thread())
|
|
843
|
-
|
|
844
|
-
**解决方案:**
|
|
845
|
-
|
|
846
|
-
**方案 1:使用配置的异步执行器**
|
|
847
|
-
```java
|
|
848
|
-
@Service
|
|
849
|
-
public class MyService {
|
|
850
|
-
@Autowired
|
|
851
|
-
private Executor asyncExecutor; // 使用 Avatar Boot 配置的执行器
|
|
852
|
-
|
|
853
|
-
public void doWork() {
|
|
854
|
-
CompletableFuture.runAsync(() -> {
|
|
855
|
-
// TraceID 自动传播
|
|
856
|
-
String traceId = ContextManager.get().getTraceId();
|
|
857
|
-
}, asyncExecutor);
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
```
|
|
861
|
-
|
|
862
|
-
**方案 2:自定义线程池应用 MdcTaskDecorator**
|
|
863
|
-
```java
|
|
864
|
-
@Configuration
|
|
865
|
-
public class ThreadPoolConfig {
|
|
866
|
-
@Autowired
|
|
867
|
-
private MdcTaskDecorator mdcTaskDecorator;
|
|
868
|
-
|
|
869
|
-
@Bean
|
|
870
|
-
public ThreadPoolTaskExecutor customExecutor() {
|
|
871
|
-
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
|
872
|
-
executor.setTaskDecorator(mdcTaskDecorator); // 关键:应用装饰器
|
|
873
|
-
executor.initialize();
|
|
874
|
-
return executor;
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
```
|
|
878
|
-
|
|
879
|
-
**方案 3:检查异步支持是否启用**
|
|
880
|
-
```yaml
|
|
881
|
-
avatar:
|
|
882
|
-
web:
|
|
883
|
-
async:
|
|
884
|
-
enabled: true # 确保为 true
|
|
885
|
-
```
|
|
886
|
-
|
|
887
|
-
### 问题 8:如何验证异步 TraceID 传播是否生效(1.0.0-SNAPSHOT+)
|
|
888
|
-
|
|
889
|
-
**验证方法:**
|
|
890
|
-
|
|
891
|
-
```java
|
|
892
|
-
@RestController
|
|
893
|
-
public class TestController {
|
|
894
|
-
|
|
895
|
-
@Autowired
|
|
896
|
-
private Executor asyncExecutor;
|
|
897
|
-
|
|
898
|
-
@GetMapping("/test-async")
|
|
899
|
-
public String testAsync() {
|
|
900
|
-
String mainTraceId = ContextManager.get().getTraceId();
|
|
901
|
-
log.info("Main thread TraceID: {}", mainTraceId);
|
|
902
|
-
|
|
903
|
-
CompletableFuture.runAsync(() -> {
|
|
904
|
-
String asyncTraceId = ContextManager.get().getTraceId();
|
|
905
|
-
log.info("Async thread TraceID: {}", asyncTraceId);
|
|
906
|
-
}, asyncExecutor).join();
|
|
907
|
-
|
|
908
|
-
return "Check logs";
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
```
|
|
912
|
-
|
|
913
|
-
**预期日志输出:**
|
|
914
|
-
```
|
|
915
|
-
[http-nio-8080-exec-1] [abc123] Main thread TraceID: abc123
|
|
916
|
-
[avatar-async-1] [abc123] Async thread TraceID: abc123
|
|
917
|
-
```
|
|
918
|
-
|
|
919
|
-
如果异步线程的 TraceID 为 null 或不一致,说明传播未生效。
|
|
920
|
-
|
|
921
|
-
## 组件参考
|
|
922
|
-
|
|
923
|
-
### 核心类
|
|
924
|
-
|
|
925
|
-
| 类 | 包 | 用途 |
|
|
926
|
-
|-------|---------|---------|
|
|
927
|
-
| `WebAutoConfiguration` | `com.iflytek.avatar.boot.config` | 主自动配置类 |
|
|
928
|
-
| `WebProperties` | `com.iflytek.avatar.boot.config` | 配置属性 |
|
|
929
|
-
| `WebMvcConfiguration` | `com.iflytek.avatar.boot.config` | MVC 配置(拦截器、CORS) |
|
|
930
|
-
| `MetricsConfiguration` | `com.iflytek.avatar.boot.config` | 指标记录器配置 |
|
|
931
|
-
| `RequestContextInterceptor` | `com.iflytek.avatar.boot.interceptor` | 请求上下文初始化 |
|
|
932
|
-
| `GlobalExceptionHandler` | `com.iflytek.avatar.boot.exception` | 全局异常处理 |
|
|
933
|
-
| `LogInfo` | `com.iflytek.avatar.boot.anno` | 方法级日志注解 |
|
|
934
|
-
| `LogInfoAspect` | `com.iflytek.avatar.boot.anno` | @LogInfo 的 AOP 切面 |
|
|
935
|
-
| `MetricsRecorder` | `com.iflytek.avatar.boot.metrics` | 指标记录工具 |
|
|
936
|
-
| `AvatarContext` | `com.iflytek.avatar.boot.context` | 请求上下文持有者(在 core 中) |
|
|
937
|
-
| `ContextManager` | `com.iflytek.avatar.boot.context` | ThreadLocal 上下文管理器(在 core 中) |
|
|
938
|
-
|
|
939
|
-
### 配置属性
|
|
940
|
-
|
|
941
|
-
| 属性 | 类型 | 默认值 | 说明 |
|
|
942
|
-
|----------|------|---------|-------------|
|
|
943
|
-
| `avatar.web.interceptor-enabled` | boolean | true | 启用请求拦截器 |
|
|
944
|
-
| `avatar.web.exception-handler-enabled` | boolean | true | 启用全局异常处理器 |
|
|
945
|
-
| `avatar.web.cors-enabled` | boolean | false | 启用 CORS |
|
|
946
|
-
| `avatar.web.interceptor.trace-id-header` | String | X-Trace-Id | TraceId 请求头名称 |
|
|
947
|
-
| `avatar.web.interceptor.include-paths` | List<String> | ["/**"] | 拦截路径 |
|
|
948
|
-
| `avatar.web.interceptor.exclude-paths` | List<String> | ["/error", "/actuator/**", ...] | 排除路径 |
|
|
949
|
-
| `avatar.web.log.request-enabled` | boolean | true | 记录请求开始 |
|
|
950
|
-
| `avatar.web.log.response-enabled` | boolean | true | 记录请求完成 |
|
|
951
|
-
| `avatar.web.log.slow-request-threshold` | long | 3000 | 慢请求阈值(毫秒) |
|
|
952
|
-
| `avatar.web.async.enabled` | boolean | true | 启用异步支持(1.0.0-SNAPSHOT+) |
|
|
953
|
-
| `avatar.web.async.core-pool-size` | int | 10 | 异步执行器核心线程数(1.0.0-SNAPSHOT+) |
|
|
954
|
-
| `avatar.web.async.max-pool-size` | int | 50 | 异步执行器最大线程数(1.0.0-SNAPSHOT+) |
|
|
955
|
-
| `avatar.web.async.queue-capacity` | int | 200 | 异步执行器队列容量(1.0.0-SNAPSHOT+) |
|
|
956
|
-
| `avatar.web.async.thread-name-prefix` | String | avatar-async- | 异步线程名前缀(1.0.0-SNAPSHOT+) |
|
|
957
|
-
| `avatar.web.tracing.micrometer-enabled` | boolean | false | 启用 Micrometer 集成(1.0.0-SNAPSHOT+) |
|
|
958
|
-
| `avatar.web.tracing.generator-type` | String | uuid | TraceID 生成策略(1.0.0-SNAPSHOT+) |
|
|
959
|
-
| `avatar.web.cors.allowed-origins` | List<String> | ["*"] | 允许的源 |
|
|
960
|
-
| `avatar.web.cors.allowed-methods` | List<String> | ["GET", "POST", ...] | 允许的 HTTP 方法 |
|
|
961
|
-
| `avatar.web.cors.allowed-headers` | List<String> | ["*"] | 允许的请求头 |
|
|
962
|
-
| `avatar.web.cors.exposed-headers` | List<String> | ["X-Trace-Id"] | 暴露的响应头 |
|
|
963
|
-
| `avatar.web.cors.allow-credentials` | boolean | true | 允许凭证 |
|
|
964
|
-
| `avatar.web.cors.max-age` | long | 3600 | 预检缓存时间(秒) |
|
|
965
|
-
|
|
966
|
-
## 依赖
|
|
967
|
-
|
|
968
|
-
此模块依赖于:
|
|
969
|
-
|
|
970
|
-
- `avatar-boot-core` - 核心功能(AvatarContext、Result 等)
|
|
971
|
-
- `spring-boot-starter-web` - Spring MVC
|
|
972
|
-
- `spring-boot-starter-validation` - 参数校验
|
|
973
|
-
- `spring-boot-starter-aop` - @LogInfo 的 AOP 支持
|
|
974
|
-
- `micrometer-core` - 指标(可选)
|
|
975
|
-
- `logstash-logback-encoder` - JSON 日志格式化
|
|
976
|
-
- `hutool-all` - 工具库(UUID、字符串处理)
|
|
977
|
-
|
|
978
|
-
## 最佳实践
|
|
979
|
-
|
|
980
|
-
1. **始终使用 Result<T> 作为 API 响应** - 确保响应格式一致
|
|
981
|
-
2. **生产环境不要禁用拦截器** - TraceId 对故障排查至关重要
|
|
982
|
-
3. **谨慎使用 @LogInfo** - 仅在关键业务方法上使用,避免日志膨胀
|
|
983
|
-
4. **根据环境配置慢请求阈值** - 开发环境可以放宽,生产环境应严格
|
|
984
|
-
5. **生产环境永远不要使用 CORS "*" 配合凭证** - 安全风险
|
|
985
|
-
6. **始终将 TraceId 传播到下游服务** - 启用分布式追踪
|
|
986
|
-
7. **使用环境特定的日志级别** - 开发环境用 DEBUG,生产环境用 INFO
|
|
987
|
-
8. **在生产环境监控指标** - 为高失败率或慢方法设置告警
|
|
988
|
-
9. **不要捕获并吞掉异常** - 让 GlobalExceptionHandler 处理它们
|
|
989
|
-
10. **在 finally 块中清理资源** - 尽管拦截器会处理上下文清理
|
|
990
|
-
|
|
991
|
-
## 版本要求
|
|
992
|
-
|
|
993
|
-
- Java 21+
|
|
994
|
-
- Spring Boot 3.5.3+
|
|
995
|
-
- Maven 3.8.6+
|
|
996
|
-
|
|
997
|
-
## 相关技能
|
|
998
|
-
|
|
999
|
-
- `avatar-boot-sdk-development` - 用于整体 Avatar Boot 架构和依赖管理
|
|
1000
|
-
- `java-spring-boot` - 用于通用 Spring Boot 开发模式
|
|
1001
|
-
- `systematic-debugging` - 用于排查此模块的问题
|
|
1002
|
-
|
|
1003
|
-
## 其他资源
|
|
1004
|
-
|
|
1005
|
-
- 模块 README:`avatar-boot-starter-web/README.md`
|
|
1006
|
-
- 配置示例:`avatar-boot-starter-web/src/main/resources/application-example.yml`
|
|
1007
|
-
- Logback 配置:`avatar-boot-starter-web/src/main/resources/logback-spring.xml`
|
|
6
|
+
# Avatar Boot Starter Web 使用指南
|
|
7
|
+
|
|
8
|
+
你是 Avatar Boot Web 模块的使用顾问与开发助手。
|
|
9
|
+
|
|
10
|
+
## 交互流程(必须遵守)
|
|
11
|
+
|
|
12
|
+
**每次被触发时,先通过 AskUserQuestion 工具询问用户意图:**
|
|
13
|
+
|
|
14
|
+
问题:"您好!我是 Avatar Boot Web 模块助手,请问您需要哪方面的帮助?"
|
|
15
|
+
选项:
|
|
16
|
+
1. **快速接入** - 我想把 avatar-boot-starter-web 集成到我的项目中
|
|
17
|
+
2. **功能使用** - 我想了解某个具体功能的用法(异常处理、日志、TraceId、@LogInfo、指标监控等)
|
|
18
|
+
3. **配置调整** - 我想自定义模块的配置项
|
|
19
|
+
4. **自定义扩展** - 我想扩展或覆盖模块的默认行为
|
|
20
|
+
|
|
21
|
+
**根据用户选择进入对应模式:**
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
### 模式一:快速接入
|
|
26
|
+
|
|
27
|
+
**先用 Read 工具读取** `references/快速接入指南.md`,然后引导用户完成以下步骤:
|
|
28
|
+
|
|
29
|
+
1. 添加 Maven 依赖
|
|
30
|
+
2. 确认无需额外配置(开箱即用)
|
|
31
|
+
3. 验证功能是否生效
|
|
32
|
+
|
|
33
|
+
完成后询问用户是否需要了解具体功能的使用方式。
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
### 模式二:功能使用
|
|
38
|
+
|
|
39
|
+
用 AskUserQuestion 询问用户关注的功能:
|
|
40
|
+
|
|
41
|
+
问题:"您想了解哪个功能的使用方式?"
|
|
42
|
+
选项:
|
|
43
|
+
1. **全局异常处理** - 统一异常响应、业务异常抛出
|
|
44
|
+
2. **请求上下文(AvatarContext)** - TraceId 获取、客户端 IP、请求耗时
|
|
45
|
+
3. **@LogInfo 方法日志注解** - 方法级日志记录、慢方法检测
|
|
46
|
+
4. **结构化日志体系** - 日志格式、日志文件、环境配置
|
|
47
|
+
5. **指标监控(Micrometer)** - 方法调用统计、执行时间统计
|
|
48
|
+
|
|
49
|
+
**根据用户选择,用 Read 工具按下方「文档读取路由」加载对应文档,然后给出具体指导。**
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
### 模式三:配置调整
|
|
54
|
+
|
|
55
|
+
**先用 Read 工具读取** `references/配置参考.md`,然后:
|
|
56
|
+
|
|
57
|
+
用 AskUserQuestion 询问用户要调整的配置项:
|
|
58
|
+
|
|
59
|
+
问题:"您需要调整哪方面的配置?"
|
|
60
|
+
选项:
|
|
61
|
+
1. **拦截器配置** - 拦截路径、排除路径、TraceId 请求头名称
|
|
62
|
+
2. **日志配置** - 请求/响应日志开关、慢请求阈值
|
|
63
|
+
3. **指标监控配置** - 启用/禁用指标
|
|
64
|
+
4. **关闭某个功能** - 关闭拦截器或全局异常处理
|
|
65
|
+
|
|
66
|
+
根据用户选择,从读取到的配置文档中提取对应内容,给出**精准的 YAML 配置示例**。
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
### 模式四:自定义扩展
|
|
71
|
+
|
|
72
|
+
用 AskUserQuestion 询问用户要扩展的内容:
|
|
73
|
+
|
|
74
|
+
问题:"您需要扩展哪方面的功能?"
|
|
75
|
+
选项:
|
|
76
|
+
1. **自定义异常处理器** - 添加新的异常类型处理
|
|
77
|
+
2. **自定义拦截器** - 添加业务拦截逻辑
|
|
78
|
+
3. **自定义响应格式** - 修改 Result 结构
|
|
79
|
+
|
|
80
|
+
**用 Read 工具读取** `references/自定义扩展指南.md`,然后给出对应的代码示例。
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 行为准则
|
|
85
|
+
|
|
86
|
+
1. **回答要具体**:引用具体的类名、注解、配置项等,不要泛泛而谈
|
|
87
|
+
2. **主动提醒**:回答某个功能时,主动提醒注意事项和常见误区
|
|
88
|
+
3. **逐步引导**:回答完当前问题后,提示用户下一步可以做什么
|
|
89
|
+
4. **使用中文回答**
|
|
90
|
+
5. **版本说明**:
|
|
91
|
+
- 本模块要求 Java 21+、Spring Boot 3.5.3+
|
|
92
|
+
- 使用 `jakarta.*` 命名空间,不支持 `javax.*`
|
|
93
|
+
- 自动配置使用 `AutoConfiguration.imports`,不使用 `spring.factories`
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 文档读取路由
|
|
98
|
+
|
|
99
|
+
> 所有路径相对于 skill 目录 `docs/skills/avatar-boot-starter-web-skill/`
|
|
100
|
+
|
|
101
|
+
### 模式一:快速接入
|
|
102
|
+
- `references/快速接入指南.md`
|
|
103
|
+
|
|
104
|
+
### 模式二:功能使用
|
|
105
|
+
|
|
106
|
+
| 功能 | 需读取的文件 |
|
|
107
|
+
|:--|:--|
|
|
108
|
+
| 全局异常处理 | `references/功能-全局异常处理.md` |
|
|
109
|
+
| 请求上下文(AvatarContext) | `references/功能-请求上下文.md` |
|
|
110
|
+
| @LogInfo 方法日志注解 | `references/功能-LogInfo注解.md` |
|
|
111
|
+
| 结构化日志体系 | `references/功能-日志体系.md` |
|
|
112
|
+
| 指标监控(Micrometer) | `references/功能-指标监控.md` |
|
|
113
|
+
|
|
114
|
+
### 模式三:配置调整
|
|
115
|
+
- `references/配置参考.md`
|
|
116
|
+
|
|
117
|
+
### 模式四:自定义扩展
|
|
118
|
+
- `references/自定义扩展指南.md`
|
|
119
|
+
|
|
120
|
+
### 按需补充
|
|
121
|
+
|
|
122
|
+
在对话过程中,根据用户需求追加读取:
|
|
123
|
+
- 用户遇到依赖问题 → `references/快速接入指南.md`(依赖说明部分)
|
|
124
|
+
- 用户询问注意事项 → `references/注意事项.md`
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## 通用参考信息
|
|
129
|
+
|
|
130
|
+
### 核心类速查
|
|
131
|
+
|
|
132
|
+
| 类/注解 | 包路径 | 用途 |
|
|
133
|
+
|:--|:--|:--|
|
|
134
|
+
| `AvatarContext` | `com.iflytek.avatar.boot.context` | 请求上下文数据对象 |
|
|
135
|
+
| `ContextManager` | `com.iflytek.avatar.boot.context` | 获取/设置请求上下文 |
|
|
136
|
+
| `Result<T>` | `com.iflytek.avatar.boot.entity.response` | 统一响应封装 |
|
|
137
|
+
| `ResultCode` | `com.iflytek.avatar.boot.entity.response` | 响应状态码枚举 |
|
|
138
|
+
| `BusinessException` | `com.iflytek.avatar.boot.exception` | 业务异常基类 |
|
|
139
|
+
| `BadRequestException` | `com.iflytek.avatar.boot.exception` | 请求参数异常 |
|
|
140
|
+
| `GlobalExceptionHandler` | `com.iflytek.avatar.boot.exception` | 全局异常处理器 |
|
|
141
|
+
| `@LogInfo` | `com.iflytek.avatar.boot.anno` | 方法日志注解 |
|
|
142
|
+
|
|
143
|
+
### 默认配置值
|
|
144
|
+
|
|
145
|
+
| 配置项 | 默认值 |
|
|
146
|
+
|:--|:--|
|
|
147
|
+
| `avatar.web.interceptor-enabled` | `true` |
|
|
148
|
+
| `avatar.web.exception-handler-enabled` | `true` |
|
|
149
|
+
| `avatar.web.interceptor.trace-id-header` | `X-Trace-Id` |
|
|
150
|
+
| `avatar.web.interceptor.include-paths` | `/**` |
|
|
151
|
+
| `avatar.web.log.request-enabled` | `false` |
|
|
152
|
+
| `avatar.web.log.response-enabled` | `false` |
|
|
153
|
+
| `avatar.web.log.slow-request-threshold` | `3000`(ms) |
|
|
154
|
+
| `avatar.web.metrics.enabled` | `true` |
|