cdspec 0.1.1 → 0.1.4
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/dist/cli.js +1 -40
- package/dist/config/default.js +1 -48
- package/dist/config/loader.js +1 -30
- package/dist/config/path.js +1 -11
- package/dist/config/types.js +1 -1
- package/dist/skill-core/adapters/claudecode-adapter.js +1 -35
- package/dist/skill-core/adapters/codex-adapter.js +1 -28
- package/dist/skill-core/adapters/iflow-adapter.js +1 -39
- package/dist/skill-core/adapters/index.js +1 -34
- package/dist/skill-core/adapters/shared.js +1 -36
- package/dist/skill-core/manifest-loader.js +1 -60
- package/dist/skill-core/scaffold.js +1 -169
- package/dist/skill-core/service.js +1 -109
- package/dist/skill-core/tool-interactions.js +1 -70
- package/dist/skill-core/types.js +1 -1
- package/dist/skill-core/validator.js +1 -25
- package/dist/utils/frontmatter.js +1 -40
- package/dist/utils/fs.js +1 -37
- package/package.json +11 -2
- package/templates/{standards-backend → backend-standard}/SKILL.md +55 -55
- package/templates/backend-standard/agents/openai.yaml +4 -0
- package/templates/{standards-backend → backend-standard}/references/DDD/346/236/266/346/236/204/347/272/246/346/235/237.md +103 -103
- package/templates/{standards-backend → backend-standard}/references/JUC/345/271/266/345/217/221/350/247/204/350/214/203.md +232 -232
- package/templates/{standards-backend → backend-standard}/references//344/274/240/347/273/237/344/270/211/345/261/202/346/236/266/346/236/204/347/272/246/346/235/237.md +35 -35
- package/templates/{standards-backend → backend-standard}/references//345/220/216/347/253/257/345/274/200/345/217/221/350/247/204/350/214/203.md +49 -49
- package/templates/{standards-backend → backend-standard}/references//346/225/260/346/215/256/345/272/223/350/256/276/350/256/241/350/247/204/350/214/203.md +116 -116
- package/templates/{standards-backend → backend-standard}/references//350/256/276/350/256/241/346/250/241/345/274/217/350/220/275/345/234/260/346/211/213/345/206/214.md +395 -395
- package/templates/{frontend-develop-standard → frontend-standard}/SKILL.md +63 -63
- package/templates/frontend-standard/agents/openai.yaml +4 -0
- package/templates/{frontend-develop-standard/references/frontend_develop_standard.md → frontend-standard/references/frontend_standard.md} +28 -321
- package/cdspec.config.yaml +0 -34
- package/dist/skill-core/agent-config.js +0 -40
- package/dist/task-core/parser.js +0 -70
- package/dist/task-core/service.js +0 -28
- package/dist/task-core/storage.js +0 -159
- package/dist/task-core/types.js +0 -1
- package/src/cli.ts +0 -44
- package/src/config/default.ts +0 -51
- package/src/config/loader.ts +0 -37
- package/src/config/path.ts +0 -13
- package/src/config/types.ts +0 -22
- package/src/skill-core/adapters/claudecode-adapter.ts +0 -45
- package/src/skill-core/adapters/codex-adapter.ts +0 -36
- package/src/skill-core/adapters/iflow-adapter.ts +0 -49
- package/src/skill-core/adapters/index.ts +0 -39
- package/src/skill-core/adapters/shared.ts +0 -45
- package/src/skill-core/manifest-loader.ts +0 -72
- package/src/skill-core/scaffold.ts +0 -192
- package/src/skill-core/service.ts +0 -137
- package/src/skill-core/tool-interactions.ts +0 -95
- package/src/skill-core/types.ts +0 -22
- package/src/skill-core/validator.ts +0 -28
- package/src/types/yaml.d.ts +0 -4
- package/src/utils/frontmatter.ts +0 -55
- package/src/utils/fs.ts +0 -41
- package/templates/frontend-develop-standard/agents/openai.yaml +0 -4
- package/templates/standards-backend/agents/openai.yaml +0 -4
- package/tests/init.test.ts +0 -63
- package/tsconfig.json +0 -16
- package/vitest.config.ts +0 -9
|
@@ -1,232 +1,232 @@
|
|
|
1
|
-
# JUC 并发规范与样例(部门版)
|
|
2
|
-
|
|
3
|
-
## 1. 总原则
|
|
4
|
-
1. 先明确是否真的需要并发,不要把并发当性能“银弹”。
|
|
5
|
-
2. 并发代码必须具备四件套:线程池边界、超时控制、异常收敛、可观测日志。
|
|
6
|
-
3. 并发优化必须配套压测或至少基线对比,不允许凭感觉上线。
|
|
7
|
-
4. 业务写操作并发时,必须先定义幂等与一致性策略。
|
|
8
|
-
|
|
9
|
-
## 2. 线程池规范
|
|
10
|
-
### 2.1 必须遵守
|
|
11
|
-
1. 业务代码禁止直接使用 `Executors` 创建通用线程池。
|
|
12
|
-
2. 必须显式设置 `corePoolSize`、`maxPoolSize`、`queueCapacity`、`RejectedExecutionHandler`。
|
|
13
|
-
3. 线程名前缀必须带业务语义,便于排障。
|
|
14
|
-
4. 必须设置优雅停机参数(等待任务完成与超时时间)。
|
|
15
|
-
|
|
16
|
-
### 2.2 推荐样例(Spring)
|
|
17
|
-
```java
|
|
18
|
-
@Configuration
|
|
19
|
-
public class BizThreadPoolConfig {
|
|
20
|
-
|
|
21
|
-
@Bean("orderAsyncExecutor")
|
|
22
|
-
public ThreadPoolTaskExecutor orderAsyncExecutor() {
|
|
23
|
-
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
|
24
|
-
executor.setCorePoolSize(8);
|
|
25
|
-
executor.setMaxPoolSize(16);
|
|
26
|
-
executor.setQueueCapacity(200);
|
|
27
|
-
executor.setKeepAliveSeconds(60);
|
|
28
|
-
executor.setThreadNamePrefix("order-async-");
|
|
29
|
-
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
|
30
|
-
executor.setWaitForTasksToCompleteOnShutdown(true);
|
|
31
|
-
executor.setAwaitTerminationSeconds(30);
|
|
32
|
-
executor.initialize();
|
|
33
|
-
return executor;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### 2.3 拒绝策略建议
|
|
39
|
-
1. `AbortPolicy`:核心链路,宁可失败暴露问题。
|
|
40
|
-
2. `CallerRunsPolicy`:允许调用方降速回压。
|
|
41
|
-
3. `Discard/DiscardOldest`:仅可用于弱一致、可丢任务场景,需业务签字。
|
|
42
|
-
|
|
43
|
-
## 3. CompletableFuture 规范
|
|
44
|
-
### 3.1 必须遵守
|
|
45
|
-
1. 优先使用业务线程池,禁止默认公共线程池污染全局。
|
|
46
|
-
2. 聚合调用必须设置整体超时。
|
|
47
|
-
3. 必须有异常兜底与降级值,禁止直接 `join` 后抛到最外层。
|
|
48
|
-
4. 合并结果前必须过滤空值与异常结果。
|
|
49
|
-
|
|
50
|
-
### 3.2 推荐样例
|
|
51
|
-
```java
|
|
52
|
-
public List<OrderView> queryOrdersAsync(List<String> ids, Executor executor) {
|
|
53
|
-
List<CompletableFuture<OrderView>> futures = ids.stream()
|
|
54
|
-
.map(id -> CompletableFuture.supplyAsync(() -> queryOne(id), executor)
|
|
55
|
-
.completeOnTimeout(OrderView.empty(id), 800, TimeUnit.MILLISECONDS)
|
|
56
|
-
.exceptionally(ex -> {
|
|
57
|
-
log.error("异步查询订单失败, id:{}", id, ex);
|
|
58
|
-
return OrderView.empty(id);
|
|
59
|
-
}))
|
|
60
|
-
.toList();
|
|
61
|
-
|
|
62
|
-
CompletableFuture<Void> all = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
|
63
|
-
all.orTimeout(2, TimeUnit.SECONDS).join();
|
|
64
|
-
|
|
65
|
-
return futures.stream()
|
|
66
|
-
.map(CompletableFuture::join)
|
|
67
|
-
.filter(OrderView::valid)
|
|
68
|
-
.toList();
|
|
69
|
-
}
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## 4. CountDownLatch 规范
|
|
73
|
-
### 4.1 使用边界
|
|
74
|
-
1. 适合“一次性协同等待”,不适合可复用屏障。
|
|
75
|
-
2. 每个 `countDown` 必须放在 `finally`,防止死等。
|
|
76
|
-
3. `await` 必须设置超时,超时后记录上下文并快速失败。
|
|
77
|
-
|
|
78
|
-
### 4.2 推荐样例
|
|
79
|
-
```java
|
|
80
|
-
public void batchHandle(List<Task> tasks, Executor executor) throws InterruptedException {
|
|
81
|
-
CountDownLatch latch = new CountDownLatch(tasks.size());
|
|
82
|
-
for (Task task : tasks) {
|
|
83
|
-
executor.execute(() -> {
|
|
84
|
-
try {
|
|
85
|
-
handleOne(task);
|
|
86
|
-
} catch (Exception ex) {
|
|
87
|
-
log.error("并发任务处理失败, taskId:{}", task.getId(), ex);
|
|
88
|
-
} finally {
|
|
89
|
-
latch.countDown();
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
boolean finished = latch.await(30, TimeUnit.SECONDS);
|
|
95
|
-
if (!finished) {
|
|
96
|
-
throw new IllegalStateException("批处理超时,存在未完成任务");
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
## 5. Semaphore 规范
|
|
102
|
-
### 5.1 适用场景
|
|
103
|
-
1. 需要限制并发访问量,如第三方接口、限连接资源、下游慢服务。
|
|
104
|
-
2. 单机内“令牌桶”式削峰,避免瞬时把下游打挂。
|
|
105
|
-
|
|
106
|
-
### 5.2 推荐样例
|
|
107
|
-
```java
|
|
108
|
-
public class ThirdPartyGateway {
|
|
109
|
-
|
|
110
|
-
private final Semaphore semaphore = new Semaphore(20, true);
|
|
111
|
-
|
|
112
|
-
public Result call(ApiReq req) throws InterruptedException {
|
|
113
|
-
boolean acquired = semaphore.tryAcquire(200, TimeUnit.MILLISECONDS);
|
|
114
|
-
if (!acquired) {
|
|
115
|
-
throw new IllegalStateException("下游繁忙,请稍后重试");
|
|
116
|
-
}
|
|
117
|
-
try {
|
|
118
|
-
return doHttpCall(req);
|
|
119
|
-
} finally {
|
|
120
|
-
semaphore.release();
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### 5.3 注意事项
|
|
127
|
-
1. `acquire` 后必须在 `finally` 中 `release`。
|
|
128
|
-
2. 优先 `tryAcquire(timeout)`,避免无限等待。
|
|
129
|
-
3. 公平锁会牺牲吞吐,默认仅在“先来先服务”强需求时启用公平参数。
|
|
130
|
-
|
|
131
|
-
## 6. ReentrantLock 规范
|
|
132
|
-
### 6.1 适用场景
|
|
133
|
-
1. 需要可中断锁、可轮询尝试锁、读写条件变量等能力。
|
|
134
|
-
2. 需要比 `synchronized` 更细粒度的锁控制和可观测性。
|
|
135
|
-
|
|
136
|
-
### 6.2 推荐样例
|
|
137
|
-
```java
|
|
138
|
-
public class OrderCache {
|
|
139
|
-
|
|
140
|
-
private final ReentrantLock lock = new ReentrantLock();
|
|
141
|
-
private final Map<String, Order> cache = new HashMap<>();
|
|
142
|
-
|
|
143
|
-
public void put(Order order) {
|
|
144
|
-
lock.lock();
|
|
145
|
-
try {
|
|
146
|
-
cache.put(order.getId(), order);
|
|
147
|
-
} finally {
|
|
148
|
-
lock.unlock();
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
public Optional<Order> get(String id) {
|
|
153
|
-
if (!lock.tryLock()) {
|
|
154
|
-
return Optional.empty();
|
|
155
|
-
}
|
|
156
|
-
try {
|
|
157
|
-
return Optional.ofNullable(cache.get(id));
|
|
158
|
-
} finally {
|
|
159
|
-
lock.unlock();
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### 6.3 注意事项
|
|
166
|
-
1. 禁止 `lock()` 后非 `finally` 解锁。
|
|
167
|
-
2. 对外部调用或 IO 逻辑不要包在锁内,避免锁膨胀。
|
|
168
|
-
3. 多锁场景必须固定加锁顺序,避免死锁。
|
|
169
|
-
|
|
170
|
-
## 7. 原子类规范(Atomic / LongAdder)
|
|
171
|
-
### 7.1 常用选择
|
|
172
|
-
1. `AtomicInteger/AtomicLong`:单值计数与状态位。
|
|
173
|
-
2. `AtomicReference`:无锁替换对象引用。
|
|
174
|
-
3. `AtomicStampedReference`:需要避免 ABA 问题。
|
|
175
|
-
4. `LongAdder`:高并发计数优于 `AtomicLong`。
|
|
176
|
-
|
|
177
|
-
### 7.2 推荐样例
|
|
178
|
-
```java
|
|
179
|
-
public class StatsCounter {
|
|
180
|
-
|
|
181
|
-
private final LongAdder success = new LongAdder();
|
|
182
|
-
private final LongAdder failed = new LongAdder();
|
|
183
|
-
private final AtomicReference<String> currentBatch = new AtomicReference<>("INIT");
|
|
184
|
-
|
|
185
|
-
public void markSuccess() {
|
|
186
|
-
success.increment();
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
public void markFailed() {
|
|
190
|
-
failed.increment();
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
public boolean switchBatch(String expect, String next) {
|
|
194
|
-
return currentBatch.compareAndSet(expect, next);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### 7.3 注意事项
|
|
200
|
-
1. 多字段一致性更新不能只靠原子类,必要时使用锁或事务。
|
|
201
|
-
2. 原子类只保证单变量原子性,不保证复合操作原子性。
|
|
202
|
-
|
|
203
|
-
## 8. 常用并发容器与同步器
|
|
204
|
-
### 8.1 ConcurrentHashMap
|
|
205
|
-
1. 高并发读写缓存首选 `ConcurrentHashMap`。
|
|
206
|
-
2. 使用 `computeIfAbsent` 避免重复初始化。
|
|
207
|
-
|
|
208
|
-
### 8.2 BlockingQueue
|
|
209
|
-
1. 生产消费解耦优先 `LinkedBlockingQueue/ArrayBlockingQueue`。
|
|
210
|
-
2. 必须设置容量上限,避免内存无界增长。
|
|
211
|
-
|
|
212
|
-
### 8.3 CopyOnWriteArrayList
|
|
213
|
-
1. 读多写少场景可用,写多场景禁止使用。
|
|
214
|
-
|
|
215
|
-
### 8.4 CyclicBarrier / Phaser
|
|
216
|
-
1. `CyclicBarrier` 适合固定参与方的分阶段任务。
|
|
217
|
-
2. `Phaser` 适合参与方动态变化的分阶段协同。
|
|
218
|
-
|
|
219
|
-
## 9. 并发反模式
|
|
220
|
-
1. `CompletableFuture.completedFuture(同步查询)` 伪异步。
|
|
221
|
-
2. 静态全局 `CountDownLatch` 工具类跨任务复用,导致串扰。
|
|
222
|
-
3. 不区分业务池和公共池,导致不同模块相互拖垮。
|
|
223
|
-
4. 捕获异常后静默吞掉,线上只能看到“卡死/超时”。
|
|
224
|
-
5. 使用无界队列和无限重试掩盖系统容量问题。
|
|
225
|
-
6. 把共享可变对象放进并发容器后误以为“业务线程安全”。
|
|
226
|
-
|
|
227
|
-
## 10. 交付前并发检查清单
|
|
228
|
-
1. 是否声明了线程池参数并解释依据。
|
|
229
|
-
2. 是否设置了超时和异常兜底。
|
|
230
|
-
3. 是否记录关键并发日志(任务数、耗时、失败数)。
|
|
231
|
-
4. 是否验证了停机或发布期间的任务收敛行为。
|
|
232
|
-
5. 是否说明共享状态的并发保护手段(锁/原子/隔离)。
|
|
1
|
+
# JUC 并发规范与样例(部门版)
|
|
2
|
+
|
|
3
|
+
## 1. 总原则
|
|
4
|
+
1. 先明确是否真的需要并发,不要把并发当性能“银弹”。
|
|
5
|
+
2. 并发代码必须具备四件套:线程池边界、超时控制、异常收敛、可观测日志。
|
|
6
|
+
3. 并发优化必须配套压测或至少基线对比,不允许凭感觉上线。
|
|
7
|
+
4. 业务写操作并发时,必须先定义幂等与一致性策略。
|
|
8
|
+
|
|
9
|
+
## 2. 线程池规范
|
|
10
|
+
### 2.1 必须遵守
|
|
11
|
+
1. 业务代码禁止直接使用 `Executors` 创建通用线程池。
|
|
12
|
+
2. 必须显式设置 `corePoolSize`、`maxPoolSize`、`queueCapacity`、`RejectedExecutionHandler`。
|
|
13
|
+
3. 线程名前缀必须带业务语义,便于排障。
|
|
14
|
+
4. 必须设置优雅停机参数(等待任务完成与超时时间)。
|
|
15
|
+
|
|
16
|
+
### 2.2 推荐样例(Spring)
|
|
17
|
+
```java
|
|
18
|
+
@Configuration
|
|
19
|
+
public class BizThreadPoolConfig {
|
|
20
|
+
|
|
21
|
+
@Bean("orderAsyncExecutor")
|
|
22
|
+
public ThreadPoolTaskExecutor orderAsyncExecutor() {
|
|
23
|
+
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
|
24
|
+
executor.setCorePoolSize(8);
|
|
25
|
+
executor.setMaxPoolSize(16);
|
|
26
|
+
executor.setQueueCapacity(200);
|
|
27
|
+
executor.setKeepAliveSeconds(60);
|
|
28
|
+
executor.setThreadNamePrefix("order-async-");
|
|
29
|
+
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
|
30
|
+
executor.setWaitForTasksToCompleteOnShutdown(true);
|
|
31
|
+
executor.setAwaitTerminationSeconds(30);
|
|
32
|
+
executor.initialize();
|
|
33
|
+
return executor;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 2.3 拒绝策略建议
|
|
39
|
+
1. `AbortPolicy`:核心链路,宁可失败暴露问题。
|
|
40
|
+
2. `CallerRunsPolicy`:允许调用方降速回压。
|
|
41
|
+
3. `Discard/DiscardOldest`:仅可用于弱一致、可丢任务场景,需业务签字。
|
|
42
|
+
|
|
43
|
+
## 3. CompletableFuture 规范
|
|
44
|
+
### 3.1 必须遵守
|
|
45
|
+
1. 优先使用业务线程池,禁止默认公共线程池污染全局。
|
|
46
|
+
2. 聚合调用必须设置整体超时。
|
|
47
|
+
3. 必须有异常兜底与降级值,禁止直接 `join` 后抛到最外层。
|
|
48
|
+
4. 合并结果前必须过滤空值与异常结果。
|
|
49
|
+
|
|
50
|
+
### 3.2 推荐样例
|
|
51
|
+
```java
|
|
52
|
+
public List<OrderView> queryOrdersAsync(List<String> ids, Executor executor) {
|
|
53
|
+
List<CompletableFuture<OrderView>> futures = ids.stream()
|
|
54
|
+
.map(id -> CompletableFuture.supplyAsync(() -> queryOne(id), executor)
|
|
55
|
+
.completeOnTimeout(OrderView.empty(id), 800, TimeUnit.MILLISECONDS)
|
|
56
|
+
.exceptionally(ex -> {
|
|
57
|
+
log.error("异步查询订单失败, id:{}", id, ex);
|
|
58
|
+
return OrderView.empty(id);
|
|
59
|
+
}))
|
|
60
|
+
.toList();
|
|
61
|
+
|
|
62
|
+
CompletableFuture<Void> all = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
|
63
|
+
all.orTimeout(2, TimeUnit.SECONDS).join();
|
|
64
|
+
|
|
65
|
+
return futures.stream()
|
|
66
|
+
.map(CompletableFuture::join)
|
|
67
|
+
.filter(OrderView::valid)
|
|
68
|
+
.toList();
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 4. CountDownLatch 规范
|
|
73
|
+
### 4.1 使用边界
|
|
74
|
+
1. 适合“一次性协同等待”,不适合可复用屏障。
|
|
75
|
+
2. 每个 `countDown` 必须放在 `finally`,防止死等。
|
|
76
|
+
3. `await` 必须设置超时,超时后记录上下文并快速失败。
|
|
77
|
+
|
|
78
|
+
### 4.2 推荐样例
|
|
79
|
+
```java
|
|
80
|
+
public void batchHandle(List<Task> tasks, Executor executor) throws InterruptedException {
|
|
81
|
+
CountDownLatch latch = new CountDownLatch(tasks.size());
|
|
82
|
+
for (Task task : tasks) {
|
|
83
|
+
executor.execute(() -> {
|
|
84
|
+
try {
|
|
85
|
+
handleOne(task);
|
|
86
|
+
} catch (Exception ex) {
|
|
87
|
+
log.error("并发任务处理失败, taskId:{}", task.getId(), ex);
|
|
88
|
+
} finally {
|
|
89
|
+
latch.countDown();
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
boolean finished = latch.await(30, TimeUnit.SECONDS);
|
|
95
|
+
if (!finished) {
|
|
96
|
+
throw new IllegalStateException("批处理超时,存在未完成任务");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## 5. Semaphore 规范
|
|
102
|
+
### 5.1 适用场景
|
|
103
|
+
1. 需要限制并发访问量,如第三方接口、限连接资源、下游慢服务。
|
|
104
|
+
2. 单机内“令牌桶”式削峰,避免瞬时把下游打挂。
|
|
105
|
+
|
|
106
|
+
### 5.2 推荐样例
|
|
107
|
+
```java
|
|
108
|
+
public class ThirdPartyGateway {
|
|
109
|
+
|
|
110
|
+
private final Semaphore semaphore = new Semaphore(20, true);
|
|
111
|
+
|
|
112
|
+
public Result call(ApiReq req) throws InterruptedException {
|
|
113
|
+
boolean acquired = semaphore.tryAcquire(200, TimeUnit.MILLISECONDS);
|
|
114
|
+
if (!acquired) {
|
|
115
|
+
throw new IllegalStateException("下游繁忙,请稍后重试");
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
return doHttpCall(req);
|
|
119
|
+
} finally {
|
|
120
|
+
semaphore.release();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 5.3 注意事项
|
|
127
|
+
1. `acquire` 后必须在 `finally` 中 `release`。
|
|
128
|
+
2. 优先 `tryAcquire(timeout)`,避免无限等待。
|
|
129
|
+
3. 公平锁会牺牲吞吐,默认仅在“先来先服务”强需求时启用公平参数。
|
|
130
|
+
|
|
131
|
+
## 6. ReentrantLock 规范
|
|
132
|
+
### 6.1 适用场景
|
|
133
|
+
1. 需要可中断锁、可轮询尝试锁、读写条件变量等能力。
|
|
134
|
+
2. 需要比 `synchronized` 更细粒度的锁控制和可观测性。
|
|
135
|
+
|
|
136
|
+
### 6.2 推荐样例
|
|
137
|
+
```java
|
|
138
|
+
public class OrderCache {
|
|
139
|
+
|
|
140
|
+
private final ReentrantLock lock = new ReentrantLock();
|
|
141
|
+
private final Map<String, Order> cache = new HashMap<>();
|
|
142
|
+
|
|
143
|
+
public void put(Order order) {
|
|
144
|
+
lock.lock();
|
|
145
|
+
try {
|
|
146
|
+
cache.put(order.getId(), order);
|
|
147
|
+
} finally {
|
|
148
|
+
lock.unlock();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public Optional<Order> get(String id) {
|
|
153
|
+
if (!lock.tryLock()) {
|
|
154
|
+
return Optional.empty();
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
return Optional.ofNullable(cache.get(id));
|
|
158
|
+
} finally {
|
|
159
|
+
lock.unlock();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 6.3 注意事项
|
|
166
|
+
1. 禁止 `lock()` 后非 `finally` 解锁。
|
|
167
|
+
2. 对外部调用或 IO 逻辑不要包在锁内,避免锁膨胀。
|
|
168
|
+
3. 多锁场景必须固定加锁顺序,避免死锁。
|
|
169
|
+
|
|
170
|
+
## 7. 原子类规范(Atomic / LongAdder)
|
|
171
|
+
### 7.1 常用选择
|
|
172
|
+
1. `AtomicInteger/AtomicLong`:单值计数与状态位。
|
|
173
|
+
2. `AtomicReference`:无锁替换对象引用。
|
|
174
|
+
3. `AtomicStampedReference`:需要避免 ABA 问题。
|
|
175
|
+
4. `LongAdder`:高并发计数优于 `AtomicLong`。
|
|
176
|
+
|
|
177
|
+
### 7.2 推荐样例
|
|
178
|
+
```java
|
|
179
|
+
public class StatsCounter {
|
|
180
|
+
|
|
181
|
+
private final LongAdder success = new LongAdder();
|
|
182
|
+
private final LongAdder failed = new LongAdder();
|
|
183
|
+
private final AtomicReference<String> currentBatch = new AtomicReference<>("INIT");
|
|
184
|
+
|
|
185
|
+
public void markSuccess() {
|
|
186
|
+
success.increment();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
public void markFailed() {
|
|
190
|
+
failed.increment();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
public boolean switchBatch(String expect, String next) {
|
|
194
|
+
return currentBatch.compareAndSet(expect, next);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### 7.3 注意事项
|
|
200
|
+
1. 多字段一致性更新不能只靠原子类,必要时使用锁或事务。
|
|
201
|
+
2. 原子类只保证单变量原子性,不保证复合操作原子性。
|
|
202
|
+
|
|
203
|
+
## 8. 常用并发容器与同步器
|
|
204
|
+
### 8.1 ConcurrentHashMap
|
|
205
|
+
1. 高并发读写缓存首选 `ConcurrentHashMap`。
|
|
206
|
+
2. 使用 `computeIfAbsent` 避免重复初始化。
|
|
207
|
+
|
|
208
|
+
### 8.2 BlockingQueue
|
|
209
|
+
1. 生产消费解耦优先 `LinkedBlockingQueue/ArrayBlockingQueue`。
|
|
210
|
+
2. 必须设置容量上限,避免内存无界增长。
|
|
211
|
+
|
|
212
|
+
### 8.3 CopyOnWriteArrayList
|
|
213
|
+
1. 读多写少场景可用,写多场景禁止使用。
|
|
214
|
+
|
|
215
|
+
### 8.4 CyclicBarrier / Phaser
|
|
216
|
+
1. `CyclicBarrier` 适合固定参与方的分阶段任务。
|
|
217
|
+
2. `Phaser` 适合参与方动态变化的分阶段协同。
|
|
218
|
+
|
|
219
|
+
## 9. 并发反模式
|
|
220
|
+
1. `CompletableFuture.completedFuture(同步查询)` 伪异步。
|
|
221
|
+
2. 静态全局 `CountDownLatch` 工具类跨任务复用,导致串扰。
|
|
222
|
+
3. 不区分业务池和公共池,导致不同模块相互拖垮。
|
|
223
|
+
4. 捕获异常后静默吞掉,线上只能看到“卡死/超时”。
|
|
224
|
+
5. 使用无界队列和无限重试掩盖系统容量问题。
|
|
225
|
+
6. 把共享可变对象放进并发容器后误以为“业务线程安全”。
|
|
226
|
+
|
|
227
|
+
## 10. 交付前并发检查清单
|
|
228
|
+
1. 是否声明了线程池参数并解释依据。
|
|
229
|
+
2. 是否设置了超时和异常兜底。
|
|
230
|
+
3. 是否记录关键并发日志(任务数、耗时、失败数)。
|
|
231
|
+
4. 是否验证了停机或发布期间的任务收敛行为。
|
|
232
|
+
5. 是否说明共享状态的并发保护手段(锁/原子/隔离)。
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
# 传统三层架构约束(Controller-Service-Mapper)
|
|
2
|
-
|
|
3
|
-
## 1. 适用范围
|
|
4
|
-
1. 业务以 CRUD 为主,规则相对简单。
|
|
5
|
-
2. 项目周期短、团队规模小、强调交付速度。
|
|
6
|
-
3. 不适合复杂跨域流程和高频业务规则变更场景。
|
|
7
|
-
|
|
8
|
-
## 2. 分层职责
|
|
9
|
-
1. Controller 层:接收请求、参数校验、统一返回,不承载复杂业务。
|
|
10
|
-
2. Service 层:承载业务逻辑、事务边界、流程控制。
|
|
11
|
-
3. Mapper/Repository 层:专注数据访问,不承载业务决策。
|
|
12
|
-
4. Convert 层:负责 DTO/VO/Entity 转换,避免污染业务层。
|
|
13
|
-
|
|
14
|
-
## 3. 强制约束
|
|
15
|
-
1. Controller 禁止直接访问 Mapper。
|
|
16
|
-
2. Service 禁止返回数据库实体给前端。
|
|
17
|
-
3. Mapper 接口仅暴露数据访问方法,命名表达查询语义。
|
|
18
|
-
4. 复杂查询优先 XML/动态 SQL,禁止拼接裸 SQL 字符串。
|
|
19
|
-
5. 事务注解放在 Service 层,避免跨层事务失控。
|
|
20
|
-
|
|
21
|
-
## 4. 代码组织建议
|
|
22
|
-
1. 包结构建议:`controller`、`service`、`service.impl`、`mapper`、`entity`、`convert`。
|
|
23
|
-
2. 类命名建议:`XxxController`、`IXxxService`、`XxxServiceImpl`、`XxxMapper`。
|
|
24
|
-
3. 使用 MyBatis-Plus 时,仍需显式表达业务规则,不要把业务混在查询构造器里。
|
|
25
|
-
|
|
26
|
-
## 5. 常见反模式
|
|
27
|
-
1. 在 Controller 写业务编排。
|
|
28
|
-
2. 在 Mapper 写业务规则判断。
|
|
29
|
-
3. Service 方法过长且无领域语义,只有流程堆砌。
|
|
30
|
-
4. 返回模型复用混乱,导致 API 和数据库实体耦合。
|
|
31
|
-
|
|
32
|
-
## 6. 交付检查
|
|
33
|
-
1. 每个接口的入参、出参、错误码是否统一。
|
|
34
|
-
2. 关键写操作是否记录中文日志。
|
|
35
|
-
3. 是否补充了最小回归测试。
|
|
1
|
+
# 传统三层架构约束(Controller-Service-Mapper)
|
|
2
|
+
|
|
3
|
+
## 1. 适用范围
|
|
4
|
+
1. 业务以 CRUD 为主,规则相对简单。
|
|
5
|
+
2. 项目周期短、团队规模小、强调交付速度。
|
|
6
|
+
3. 不适合复杂跨域流程和高频业务规则变更场景。
|
|
7
|
+
|
|
8
|
+
## 2. 分层职责
|
|
9
|
+
1. Controller 层:接收请求、参数校验、统一返回,不承载复杂业务。
|
|
10
|
+
2. Service 层:承载业务逻辑、事务边界、流程控制。
|
|
11
|
+
3. Mapper/Repository 层:专注数据访问,不承载业务决策。
|
|
12
|
+
4. Convert 层:负责 DTO/VO/Entity 转换,避免污染业务层。
|
|
13
|
+
|
|
14
|
+
## 3. 强制约束
|
|
15
|
+
1. Controller 禁止直接访问 Mapper。
|
|
16
|
+
2. Service 禁止返回数据库实体给前端。
|
|
17
|
+
3. Mapper 接口仅暴露数据访问方法,命名表达查询语义。
|
|
18
|
+
4. 复杂查询优先 XML/动态 SQL,禁止拼接裸 SQL 字符串。
|
|
19
|
+
5. 事务注解放在 Service 层,避免跨层事务失控。
|
|
20
|
+
|
|
21
|
+
## 4. 代码组织建议
|
|
22
|
+
1. 包结构建议:`controller`、`service`、`service.impl`、`mapper`、`entity`、`convert`。
|
|
23
|
+
2. 类命名建议:`XxxController`、`IXxxService`、`XxxServiceImpl`、`XxxMapper`。
|
|
24
|
+
3. 使用 MyBatis-Plus 时,仍需显式表达业务规则,不要把业务混在查询构造器里。
|
|
25
|
+
|
|
26
|
+
## 5. 常见反模式
|
|
27
|
+
1. 在 Controller 写业务编排。
|
|
28
|
+
2. 在 Mapper 写业务规则判断。
|
|
29
|
+
3. Service 方法过长且无领域语义,只有流程堆砌。
|
|
30
|
+
4. 返回模型复用混乱,导致 API 和数据库实体耦合。
|
|
31
|
+
|
|
32
|
+
## 6. 交付检查
|
|
33
|
+
1. 每个接口的入参、出参、错误码是否统一。
|
|
34
|
+
2. 关键写操作是否记录中文日志。
|
|
35
|
+
3. 是否补充了最小回归测试。
|
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
# 后端开发规范(部门版)
|
|
2
|
-
|
|
3
|
-
## 1. 命名与结构
|
|
4
|
-
1. 包名全部小写,按语义分层组织。
|
|
5
|
-
2. 类名使用大驼峰,方法/变量使用小驼峰。
|
|
6
|
-
3. 命名必须表达业务语义,避免拼音、无意义缩写、单字符变量(循环计数除外)。
|
|
7
|
-
4. 常量必须使用 `static final`,常量名全大写下划线分隔。
|
|
8
|
-
5. 枚举值全大写下划线分隔,枚举要体现业务语义。
|
|
9
|
-
|
|
10
|
-
## 2. 对象分层
|
|
11
|
-
1. `Entity`:仅做数据库映射,不承载业务流程。(老项目不改动,新项目需遵守)
|
|
12
|
-
2. `ReqDTO/RespDTO`:跨服务传输对象,仅保留必要字段。(老项目不改动,新项目需遵守)
|
|
13
|
-
3. `ReqVO/RespVO`:接口展示对象,可做展示格式适配。(老项目不改动,新项目需遵守)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
## 3. 注释与日志
|
|
17
|
-
1. 类、方法、复杂分支必须有中文注释,说明“做什么、为什么这样做”。
|
|
18
|
-
2. 关键写操作必须记录中文日志,包含业务主键与结果。
|
|
19
|
-
3. 异常场景必须记录错误原因、输入上下文。
|
|
20
|
-
4. 日志避免输出敏感信息(密钥、完整证件号、明文密码)。
|
|
21
|
-
|
|
22
|
-
## 4. 控制器与返回
|
|
23
|
-
1. Controller 仅做参数接收、校验、调用应用服务,不写业务核心逻辑。
|
|
24
|
-
2. 接口返回统一结果模型,错误码和文案来自统一枚举。
|
|
25
|
-
3. 禁止直接暴露领域对象作为对外接口返回值。
|
|
26
|
-
4. URI 命名保持语义清晰并与业务动作一致。
|
|
27
|
-
|
|
28
|
-
## 5. 异常与校验
|
|
29
|
-
1. 业务异常与系统异常分层处理,禁止一把抓 `Exception` 后直接吞掉。
|
|
30
|
-
2. 参数校验前置,尽量使用声明式校验(如 Bean Validation)。
|
|
31
|
-
3. 禁止重复、冗余校验,避免多处维护同一规则。
|
|
32
|
-
4. 比较字符串时避免空指针风险,优先常量调用 `equals`。
|
|
33
|
-
|
|
34
|
-
## 6. 并发与基础能力
|
|
35
|
-
1. 禁止直接使用 `Executors` 创建线程池,使用 `ThreadPoolExecutor` 显式配置边界。
|
|
36
|
-
2. 优先使用 `java.time` 替代 `Date` / `Calendar` / `SimpleDateFormat`。
|
|
37
|
-
3. 不使用过时 API。
|
|
38
|
-
4. 复写方法必须显式加 `@Override`。
|
|
39
|
-
|
|
40
|
-
## 7. 代码质量门禁
|
|
41
|
-
1. 提交前通过静态检查(Checkstyle/PMD/FindBugs/SonarQube)。
|
|
42
|
-
2. 新增模块必须提供最小可回归测试路径。
|
|
43
|
-
3. 出现“临时方案”时,必须补充重构计划或明确技术债登记。
|
|
44
|
-
|
|
45
|
-
## 8. 可扩展性与并发基线
|
|
46
|
-
1. 业务分支超过 3 个且预计持续增长时,优先引入策略/工厂/责任链等可扩展模式。
|
|
47
|
-
2. 外部系统字段模型不一致时,优先通过适配器隔离,不在主流程直接拼装转换。
|
|
48
|
-
3. 异步并发能力统一走线程池,禁止散落创建线程。
|
|
49
|
-
4. 并发逻辑必须具备超时、降级和错误日志,禁止无边界 `join/await`。
|
|
1
|
+
# 后端开发规范(部门版)
|
|
2
|
+
|
|
3
|
+
## 1. 命名与结构
|
|
4
|
+
1. 包名全部小写,按语义分层组织。
|
|
5
|
+
2. 类名使用大驼峰,方法/变量使用小驼峰。
|
|
6
|
+
3. 命名必须表达业务语义,避免拼音、无意义缩写、单字符变量(循环计数除外)。
|
|
7
|
+
4. 常量必须使用 `static final`,常量名全大写下划线分隔。
|
|
8
|
+
5. 枚举值全大写下划线分隔,枚举要体现业务语义。
|
|
9
|
+
|
|
10
|
+
## 2. 对象分层
|
|
11
|
+
1. `Entity`:仅做数据库映射,不承载业务流程。(老项目不改动,新项目需遵守)
|
|
12
|
+
2. `ReqDTO/RespDTO`:跨服务传输对象,仅保留必要字段。(老项目不改动,新项目需遵守)
|
|
13
|
+
3. `ReqVO/RespVO`:接口展示对象,可做展示格式适配。(老项目不改动,新项目需遵守)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## 3. 注释与日志
|
|
17
|
+
1. 类、方法、复杂分支必须有中文注释,说明“做什么、为什么这样做”。
|
|
18
|
+
2. 关键写操作必须记录中文日志,包含业务主键与结果。
|
|
19
|
+
3. 异常场景必须记录错误原因、输入上下文。
|
|
20
|
+
4. 日志避免输出敏感信息(密钥、完整证件号、明文密码)。
|
|
21
|
+
|
|
22
|
+
## 4. 控制器与返回
|
|
23
|
+
1. Controller 仅做参数接收、校验、调用应用服务,不写业务核心逻辑。
|
|
24
|
+
2. 接口返回统一结果模型,错误码和文案来自统一枚举。
|
|
25
|
+
3. 禁止直接暴露领域对象作为对外接口返回值。
|
|
26
|
+
4. URI 命名保持语义清晰并与业务动作一致。
|
|
27
|
+
|
|
28
|
+
## 5. 异常与校验
|
|
29
|
+
1. 业务异常与系统异常分层处理,禁止一把抓 `Exception` 后直接吞掉。
|
|
30
|
+
2. 参数校验前置,尽量使用声明式校验(如 Bean Validation)。
|
|
31
|
+
3. 禁止重复、冗余校验,避免多处维护同一规则。
|
|
32
|
+
4. 比较字符串时避免空指针风险,优先常量调用 `equals`。
|
|
33
|
+
|
|
34
|
+
## 6. 并发与基础能力
|
|
35
|
+
1. 禁止直接使用 `Executors` 创建线程池,使用 `ThreadPoolExecutor` 显式配置边界。
|
|
36
|
+
2. 优先使用 `java.time` 替代 `Date` / `Calendar` / `SimpleDateFormat`。
|
|
37
|
+
3. 不使用过时 API。
|
|
38
|
+
4. 复写方法必须显式加 `@Override`。
|
|
39
|
+
|
|
40
|
+
## 7. 代码质量门禁
|
|
41
|
+
1. 提交前通过静态检查(Checkstyle/PMD/FindBugs/SonarQube)。
|
|
42
|
+
2. 新增模块必须提供最小可回归测试路径。
|
|
43
|
+
3. 出现“临时方案”时,必须补充重构计划或明确技术债登记。
|
|
44
|
+
|
|
45
|
+
## 8. 可扩展性与并发基线
|
|
46
|
+
1. 业务分支超过 3 个且预计持续增长时,优先引入策略/工厂/责任链等可扩展模式。
|
|
47
|
+
2. 外部系统字段模型不一致时,优先通过适配器隔离,不在主流程直接拼装转换。
|
|
48
|
+
3. 异步并发能力统一走线程池,禁止散落创建线程。
|
|
49
|
+
4. 并发逻辑必须具备超时、降级和错误日志,禁止无边界 `join/await`。
|