Skip to content

Commit da18c0b

Browse files
committed
Revert "refactor(msgAudit): 优化SDK实例管理和资源清理逻辑"
This reverts commit add61c1.
1 parent add61c1 commit da18c0b

File tree

2 files changed

+31
-13
lines changed

2 files changed

+31
-13
lines changed

docs/giggly-pondering-turtle.md

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,11 @@ Thread C: init SDK_C → ...
5252

5353
**新增字段:**
5454
```java
55-
/** 每个线程持有独立 SDK 实例,懒初始化,线程内跨调用复用 */
55+
/** 每个线程持有独立SDK实例 */
5656
private final ThreadLocal<Long> threadLocalSdk = new ThreadLocal<>();
57+
58+
/** 跟踪所有已创建SDK,用于统一清理 */
59+
private final Set<Long> managedSdks = ConcurrentHashMap.newKeySet();
5760
```
5861

5962
**废弃字段/方法:**
@@ -74,6 +77,7 @@ private long getOrInitThreadLocalSdk() throws WxErrorException {
7477
}
7578
long newSdk = createSdk();
7679
threadLocalSdk.set(newSdk);
80+
managedSdks.add(newSdk);
7781
log.info("线程 [{}] 初始化会话存档SDK成功,sdk={}", Thread.currentThread().getName(), newSdk);
7882
return newSdk;
7983
}
@@ -95,17 +99,22 @@ public void closeThreadLocalSdk() {
9599
Long sdk = threadLocalSdk.get();
96100
if (sdk != null && sdk > 0) {
97101
Finance.DestroySdk(sdk);
102+
managedSdks.remove(sdk);
98103
threadLocalSdk.remove();
99104
log.info("线程 [{}] 关闭会话存档SDK,sdk={}", Thread.currentThread().getName(), sdk);
100105
}
101106
}
102107

103108
/**
104-
* 等同于 closeThreadLocalSdk(),无法感知其他线程的SDK。
105-
* 不再遍历集合销毁所有SDK(已去掉 managedSdks 追踪)。
109+
* 关闭所有线程持有的SDK。应用关闭时调用(如Spring @PreDestroy / Shutdown Hook)。
106110
*/
107111
public void closeAllSdks() {
108-
closeThreadLocalSdk();
112+
managedSdks.forEach(sdk -> {
113+
Finance.DestroySdk(sdk);
114+
log.info("关闭会话存档SDK,sdk={}", sdk);
115+
});
116+
managedSdks.clear();
117+
threadLocalSdk.remove();
109118
}
110119
```
111120

@@ -114,10 +123,10 @@ public void closeAllSdks() {
114123
- 移除 try-finally 中的 `releaseSdk(sdk)` 调用(SDK不再每次释放)
115124
- 方法变得更简洁:直接使用sdk,无需包装计数
116125

117-
**保留旧API方法(getChatDatas / getDecryptData / getChatPlainText / getMediaFile):**
126+
**保留旧API方法不变(getChatDatas / getDecryptData / getChatPlainText / getMediaFile):**
118127
- 保持 @Deprecated 标注
119-
- `getChatDatas` 仅将 `initSdk()` 替换为 `getOrInitThreadLocalSdk()`(因 initSdk 已移除,必须改),其余逻辑、注释、代码风格完全不动
120-
- `getDecryptData` / `getChatPlainText` / `getMediaFile` 两个重载:**完全不改动**(保留原注释、`e.printStackTrace()` 等)
128+
- 内部调用改为 `getOrInitThreadLocalSdk()` 以保持一致性(旧方法也受益于ThreadLocal)
129+
- 移除对 `initSdk()` 的依赖
121130

122131
### 2. WxCpMsgAuditService(接口新增)
123132

@@ -129,8 +138,8 @@ public void closeAllSdks() {
129138
void closeThreadLocalSdk();
130139

131140
/**
132-
* 等同于 closeThreadLocalSdk(),无法感知其他线程的SDK
133-
* 适用于应用关闭时(如Spring Bean销毁阶段)清理当前线程资源
141+
* 关闭所有会话存档SDK实例
142+
* 适用于应用关闭时(如Spring Bean销毁阶段)统一释放资源
134143
*/
135144
void closeAllSdks();
136145
```
@@ -182,8 +191,6 @@ try {
182191
2. **独立线程无需显式关闭**:线程销毁时JVM会回收,但 `Finance.DestroySdk()` 不会自动调用。若关注资源,建议加 finally 清理。
183192
3. **多企业(多CorpId)场景**`threadLocalSdk` 是实例字段(非static),不同 `WxCpMsgAuditServiceImpl` 实例(不同企业)的ThreadLocal独立,互不影响。
184193
4. **库加载幂等性**`Finance.loadingLibraries()` 底层调用 `System.load()`,JVM保证同一库不重复加载,多线程并发调用安全。
185-
5. **不要手动调用 `Finance.DestroySdk()`**:旧测试代码中的 `Finance.DestroySdk(chatDatas.getSdk())` 会直接销毁 ThreadLocal 管理的 SDK,必须删除。
186-
6. **`closeAllSdks()` 的局限性**:不追踪所有SDK,只清理当前线程,语义为"尽力清理"。非线程池场景若不调用 `closeThreadLocalSdk()`,原生SDK内存会泄漏到JVM退出,但进程退出后OS会回收。
187194

188195
---
189196

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import java.util.Collections;
2424
import java.util.LinkedList;
2525
import java.util.List;
26+
import java.util.Set;
27+
import java.util.concurrent.ConcurrentHashMap;
2628
import java.util.function.Consumer;
2729

2830
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.MsgAudit.*;
@@ -40,6 +42,9 @@ public class WxCpMsgAuditServiceImpl implements WxCpMsgAuditService {
4042
/** 每个线程持有独立 SDK 实例,懒初始化,线程内跨调用复用 */
4143
private final ThreadLocal<Long> threadLocalSdk = new ThreadLocal<>();
4244

45+
/** 跟踪所有已创建的 SDK,用于 closeAllSdks() 统一清理 */
46+
private final Set<Long> managedSdks = ConcurrentHashMap.newKeySet();
47+
4348
@Override
4449
public WxCpChatDatas getChatDatas(long seq, @NonNull long limit, String proxy, String passwd,
4550
@NonNull long timeout) throws Exception {
@@ -79,6 +84,7 @@ private long getOrInitThreadLocalSdk() throws WxErrorException {
7984
}
8085
long newSdk = createSdk();
8186
threadLocalSdk.set(newSdk);
87+
managedSdks.add(newSdk);
8288
log.info("线程 [{}] 初始化会话存档SDK成功,sdk={}", Thread.currentThread().getName(), newSdk);
8389
return newSdk;
8490
}
@@ -143,15 +149,20 @@ public void closeThreadLocalSdk() {
143149
Long sdk = threadLocalSdk.get();
144150
if (sdk != null && sdk > 0) {
145151
Finance.DestroySdk(sdk);
152+
managedSdks.remove(sdk);
146153
threadLocalSdk.remove();
147154
log.info("线程 [{}] 关闭会话存档SDK,sdk={}", Thread.currentThread().getName(), sdk);
148155
}
149156
}
150157

151158
@Override
152159
public void closeAllSdks() {
153-
// 无法感知其他线程的SDK,只清理当前线程
154-
closeThreadLocalSdk();
160+
managedSdks.forEach(sdk -> {
161+
Finance.DestroySdk(sdk);
162+
log.info("关闭会话存档SDK,sdk={}", sdk);
163+
});
164+
managedSdks.clear();
165+
threadLocalSdk.remove();
155166
}
156167

157168
@Override

0 commit comments

Comments
 (0)