From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master
---
jnpf-biz-common/jnpf-audit-sdk/src/main/java/jnpf/audit/sdk/AuditTxHolder.java | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 210 insertions(+), 0 deletions(-)
diff --git a/jnpf-biz-common/jnpf-audit-sdk/src/main/java/jnpf/audit/sdk/AuditTxHolder.java b/jnpf-biz-common/jnpf-audit-sdk/src/main/java/jnpf/audit/sdk/AuditTxHolder.java
new file mode 100644
index 0000000..4723ed6
--- /dev/null
+++ b/jnpf-biz-common/jnpf-audit-sdk/src/main/java/jnpf/audit/sdk/AuditTxHolder.java
@@ -0,0 +1,210 @@
+package jnpf.audit.sdk;
+
+import jnpf.audit.AuditApiConsts;
+import jnpf.audit.model.AuditEventDTO;
+import jnpf.util.RandomUtil;
+import org.slf4j.MDC;
+import org.springframework.transaction.support.TransactionSynchronization;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 浜嬪姟绾у璁$紦鍐� holder锛坰pec 搂3.3/搂5.5 濂戠害鐨勬渶灏忓疄鐜帮級銆�
+ *
+ * <p>鑱岃矗锛氭妸鍚屼竴浜嬪姟鍐呮彁浜ょ殑瀹¤浜嬩欢缂撳啿鍒� afterCommit 鎵嶅紓姝ュ彂鍑猴紙鍥炴粴涓嶅彂锛夛紱operationId 鐨�
+ * 鐢熸垚涓� MDC 鍐欏叆缁熶竴褰掓湰绫诲崟婧愮鐞嗭紙缁堥獙#6锛歝ollector 鍏堝啓 MDC 浼氱牬鍧� previousMdc 璇箟锛夈��
+ *
+ * <p><b>operationId 璇箟锛圡2 spec 搂2锛�</b>锛氬綊灞炴渶澶栧眰鐨勩�屾搷浣滀綔鐢ㄥ煙銆嶏紙{@link #beginOperation}
+ * 杩斿洖鐨� OperationScope锛夛紝浣滅敤鍩熷唴鐨勫叏閮ㄤ簨鍔♀�斺�斿惈 REQUIRES_NEW 瀛愪簨鍔♀�斺�斿叡浜悓涓�涓� id锛�
+ * 娌℃湁浣滅敤鍩熸椂閫�鍖栦负姣忎釜浜嬪姟鑷繁涓�涓� id銆傜紦鍐蹭粛鎸変簨鍔″垝鍒嗭紙鍥炴粴涓嶅彂鐨勮涔変笉鍙橈級锛�
+ * 鍙槸銆岀紦鍐茶韩浠姐�嶄笌銆屾搷浣滆韩浠姐�嶈嚜姝よВ鑰︺��
+ *
+ * <p>鍏ㄧ被鍙湁涓�鏉� id 瑙勫垯锛�<b>鍐冲畾 id 鏃跺厛璇� MDC锛屾湁鍊煎垯娌跨敤锛屾棤鍊兼墠鐢熸垚</b>鈥斺��
+ * {@link #submit} 鏃犱簨鍔″垎鏀�亄@link #beginOperation} 鏃犱簨鍔″垎鏀�亄@link #createBuffer}
+ * 涓夊涓�鑷达紝鏃犱緥澶栥�傝法浜嬪姟锛圧EQUIRES_NEW锛夌殑娌跨敤鍦ㄦ寕璧风偣鐢变袱鏉¢�斿緞鎵挎帴锛�
+ * {@code previousMdc} 闈� null 鏃堕潬瀹冩湰韬紝涓� null 鏃堕潬 {@code TxAuditBuffer.scopeOwned}鈥斺��
+ * 涓よ�呯殑绛変环鎬т緷璧栦笅闈� {@link #createBuffer} 澶勬爣鏄庣殑涓嶅彉閲忋��
+ *
+ * <p>鏈被鐨勬椂搴忔敞閲婂搴斾簨鍔$骇缂撳啿鐨勫苟鍙戞椂搴忓绾︼紝鍧囩粡杩囬獙璇佲�斺�旈噸鏋勬椂涓嶈闅忔墜鍒犳敼锛�
+ * 姣忎竴澶勯兘瀵瑰簲涓�涓湡瀹炲瓨鍦ㄨ繃鐨勭珵鎬佸満鏅��
+ * 鍥炲綊瀹堝崼锛歿@code bash tasks/audit-opid-checks.sh}锛堝崄涓�椤瑰苟鍙戞椂搴忕煩闃碉級銆�
+ * 骞冲彴闆姳宸ュ叿缁忕幇鍦烘牳瀹炰负 {@link RandomUtil#uuId()}锛�= {@code String.valueOf(YitIdHelper.nextId())}锛夈��
+ */
+public class AuditTxHolder {
+ private static final Object RESOURCE_KEY = new Object();
+
+ /** 浜嬪姟绾х紦鍐诧細{operationId + 涓嶅彲鍙樹簨浠跺垪琛▆锛汳DC 淇濆瓨/鎭㈠闃茬嚎绋嬫睜涓插彿锛堣瘎瀹�#6锛� */
+ static class TxAuditBuffer {
+ final String operationId;
+ final String previousMdc; // 杩涘叆鍓嶇殑 MDC 鏃у�硷紝afterCompletion 鎭㈠
+ final List<AuditEventDTO> events = new ArrayList<>();
+ /**
+ * 浣滅敤鍩熸槸鍚�**缁忕敱 {@link #beginOperation} 鐨勪簨鍔″垎鏀�**鎸傚湪鏈� buffer 涓娿��
+ *
+ * <p><b>娉ㄦ剰瀹冧笉绛変簬銆屾湰 buffer 鐨� id 褰掑睘鏌愪釜浣滅敤鍩熴��</b>锛氬舰鎬佺敳锛堜綔鐢ㄥ煙鍦ㄤ簨鍔″寮�鍚��
+ * buffer 鐢� {@link #submit} 鍦ㄤ簨鍔″唴鍒涘缓锛変笅 id 鍚屾牱褰掑睘璇ヤ綔鐢ㄥ煙锛屼絾鏈爣璁颁负 false鈥斺��
+ * 閭g褰㈡�佺殑娌跨敤鐢� {@code previousMdc} 鎵挎帴锛屼笉璧版湰鏍囪銆傛湰鏍囪鍙礋璐hˉ涓�
+ * {@code previousMdc == null} 閭d竴鏍笺��
+ *
+ * <p>涓轰粈涔堥渶瑕佸畠锛氫綔鐢ㄥ煙鐢变簨鍔″垎鏀嚜宸卞垱寤烘椂 previousMdc 鎭掍负 null锛屾鏃惰嫢鎸傝捣鐐规寜
+ * previousMdc 鎭㈠浼氭妸 MDC 娓呯┖銆佸唴灞傚瓙浜嬪姟鍙︾敓鎴� id 鈫� 鍚屼竴娆℃搷浣滃垎鍙�
+ * 锛坰pec 搂1.3锛涜繖姝f槸浠婃棩 lims 鍥涘鐨勪簨鍔″舰鎬侊級銆�
+ *
+ * <p>闈� final锛氫綔鐢ㄥ煙鍙兘**鏅氫簬** buffer 鍑虹幇锛堝眰 1 鍏堝缓 buffer锛岄殢鍚庢墠杩涘叆鏍囨敞鏂规硶锛�
+ * spec 搂4 褰㈡�佷竵锛夛紝鏁� beginOperation 鐨勫垱寤轰笌澶嶇敤涓ゆ潯璺緞閮借缃綅銆�
+ * buffer 缁戝湪 TSM 浜嬪姟璧勬簮涓娿�佺嚎绋嬪唴鐙崰锛屾棤骞跺彂鍐欓闄┿��
+ */
+ boolean scopeOwned;
+ TxAuditBuffer(String operationId, String previousMdc) {
+ this.operationId = operationId; this.previousMdc = previousMdc;
+ }
+ }
+
+ /** operationId 鐨勭敓鎴愪笌 MDC 鍐欏叆缁熶竴褰掓湰绫荤鐞嗭紙缁堥獙#6锛歝ollector 鍏堝啓 MDC 浼氱牬鍧� previousMdc 璇箟锛� */
+ public static void submit(AuditEventDTO event, AuditEventPublisher publisher) {
+ if (!TransactionSynchronizationManager.isSynchronizationActive()) {
+ String outerMdc = MDC.get(AuditApiConsts.MDC_OPERATION_ID);
+ String opId = event.getOperationId() != null ? event.getOperationId()
+ : (outerMdc != null ? outerMdc : RandomUtil.uuId()); // 骞冲彴闆姳宸ュ叿锛岀被鍚嶅鐓х幇鍦�
+ publisher.publishAsync(Collections.singletonList(event.toBuilder().operationId(opId).build()));
+ if (outerMdc == null) {
+ MDC.remove(AuditApiConsts.MDC_OPERATION_ID); // 鑷繁娌″啓杩囧氨淇濇寔骞插噣
+ }
+ return;
+ }
+ TxAuditBuffer buffer = (TxAuditBuffer) TransactionSynchronizationManager.getResource(RESOURCE_KEY);
+ if (buffer == null) {
+ buffer = createBuffer(publisher);
+ }
+ buffer.events.add(event.toBuilder().operationId(buffer.operationId).build());
+ }
+
+ /** 鎿嶄綔浣滅敤鍩燂細close() 鍙湪**鏃犱簨鍔�**鍒嗘敮闇�瑕佹仮澶� MDC锛涙湁浜嬪姟鏃剁敱 afterCompletion 缁熶竴鎭㈠銆� */
+ public interface OperationScope extends AutoCloseable {
+ String operationId();
+ @Override void close(); // 瑕嗗啓鎺� AutoCloseable 鐨� throws Exception锛岃皟鐢ㄦ柟鏃犻渶 catch
+ }
+
+ /**
+ * getOrCreate 璇箟锛圡2 濂戠害鍏戠幇锛孧1 宸插湪 currentOperationId 鐨� javadoc 棰勫憡锛夛細
+ * 杩涘叆涓氬姟鏂规硶鏃跺嵆纭繚銆屾湰浜嬪姟鏈� operationId 涓斿凡鍐欏叆 MDC銆嶏紝渚涘唴灞傛棫 BizLogAspect 璇诲彇銆�
+ *
+ * <p>涓轰粈涔堜笉鑳介潬 {@link #submit}锛歴ubmit 鍙戠敓鍦� proceed() 涔嬪悗锛岃�屽唴灞傛棫鍒囬潰鍐欐棩蹇楁洿鏃╋紝
+ * 閭f椂 MDC 杩樻病鍊� 鈫� A/B 閰嶄笉涓婂銆�
+ *
+ * <p>MDC 鐢熷懡鍛ㄦ湡浠嶉攣鍦ㄦ湰绫讳竴澶勶紙鍗曟簮濂戠害锛夛細鏈変簨鍔¤蛋 afterCompletion 鎭㈠锛�
+ * 鏃犱簨鍔$敱杩斿洖鐨� scope.close() 鎭㈠鈥斺�斾袱鏉¤矾寰勯兘淇濆瓨杩涘叆鍓嶆棫鍊硷紝闃茬嚎绋嬫睜澶嶇敤涓插彿銆�
+ */
+ public static OperationScope beginOperation(AuditEventPublisher publisher) {
+ return beginOperation(publisher, null);
+ }
+
+ /**
+ * 浣跨敤鍙俊涓氬姟鍑瘉娲剧敓鐨勬樉寮忓叧鑱旈敭寮�鍚綔鐢ㄥ煙锛涘凡鏈夊灞備綔鐢ㄥ煙鏃朵粛浠ュ灞備负鍑嗐��
+ */
+ public static OperationScope beginOperation(AuditEventPublisher publisher, String preferredOperationId) {
+ if (!TransactionSynchronizationManager.isSynchronizationActive()) {
+ final String previousMdc = MDC.get(AuditApiConsts.MDC_OPERATION_ID);
+ final String opId = previousMdc != null ? previousMdc
+ : (preferredOperationId != null ? preferredOperationId : RandomUtil.uuId());
+ MDC.put(AuditApiConsts.MDC_OPERATION_ID, opId);
+ return new OperationScope() {
+ @Override public String operationId() { return opId; }
+ @Override public void close() { restoreMdc(previousMdc); }
+ };
+ }
+ TxAuditBuffer buffer = (TxAuditBuffer) TransactionSynchronizationManager.getResource(RESOURCE_KEY);
+ if (buffer == null) {
+ buffer = createBuffer(publisher, preferredOperationId);
+ }
+ // 浣滅敤鍩熸爣璁帮細鍒涘缓涓庡鐢ㄤ袱鏉¤矾寰勯兘瑕佺疆锛坰pec 搂4 褰㈡�佷竵鈥斺�斿眰 1 鍙兘鍏堝缓浜� buffer锛�
+ // 浣滅敤鍩熸櫄浜庡畠鍑虹幇锛涘彧鍦ㄥ垱寤鸿矾寰勭疆浣嶄細璁╄褰㈡�佺殑 REQUIRES_NEW 鍐呭眰閲嶆柊鍒嗗弶锛�
+ buffer.scopeOwned = true;
+ final String opId = buffer.operationId;
+ return new OperationScope() {
+ @Override public String operationId() { return opId; }
+ @Override public void close() { /* 鏈変簨鍔★細MDC 鐢� afterCompletion 鎭㈠锛屾澶勫埢鎰� no-op */ }
+ };
+ }
+
+ private static TxAuditBuffer createBuffer(final AuditEventPublisher publisher) {
+ return createBuffer(publisher, null);
+ }
+
+ private static TxAuditBuffer createBuffer(final AuditEventPublisher publisher, String preferredOperationId) {
+ // 鍏抽敭鏃跺簭锛氬厛淇濆瓨澶栧眰鏃у�硷紝鍐嶅喅瀹氭湰浜嬪姟 operationId 骞跺啓 MDC锛堢粓楠�#6锛�
+ String previousMdc = MDC.get(AuditApiConsts.MDC_OPERATION_ID);
+ // M2 璇箟锛坰pec 搂2锛夛細operationId 褰掑睘鏈�澶栧眰鎿嶄綔浣滅敤鍩熲�斺�擬DC 宸叉湁鍊煎嵆浠h〃澶栧眰宸叉湁
+ // 浣滅敤鍩燂紝涓�寰嬫部鐢紱鏃犲�兼墠鐢熸垚銆備笌 submit(:42)/beginOperation(:77) 涓ゆ潯鏃犱簨鍔″垎鏀殑
+ // 鍐欐硶鍦ㄦ鎷夐綈锛屽叏绫诲彧鏈変竴鏉¤鍒欙細"鍏堢湅 MDC锛屾湁鍒欐部鐢�"銆�
+ //
+ // 鈿狅笍 鏈纭珛涓�鏉�**鍏ㄧ被渚濊禆鐨勪笉鍙橀噺**锛氬嚒鏈柟娉曚骇鍑虹殑 buffer锛�
+ // previousMdc != null 鉄� operationId == previousMdc
+ // suspend 鐨勪笁鐩紙scopeOwned ? operationId : previousMdc锛夋鏄潬瀹冭涓ゆ敮娈婇�斿悓褰掆�斺��
+ // previousMdc 闈� null 鏃朵袱鏀彇鍊煎繀鐒剁浉绛夛紝鏁呬笁鐩彧鍦� previousMdc == null 鏃舵墠鐪熸鍒嗗矓
+ // 锛堝嵆琛屼负鍙樻洿鍗婂緞 = spec 搂4 褰㈡�佷笝/涓�/鎴婏級銆�**鑻ュ皢鏉ョ粰 id 鍐冲畾閫昏緫鍔犳梺璺紙渚嬪鍏佽璋冪敤鏂�
+ // 鏄惧紡浼犲叆 id锛夎�屾墦鐮磋涓嶅彉閲忥紝suspend 鐨勭浜屾敮浼氶潤榛樺け鍘绘部鐢ㄨ兘鍔涒�斺�旀敼杩欓噷鍏堝幓鐪� suspend銆�**
+ final TxAuditBuffer created = new TxAuditBuffer(
+ previousMdc != null ? previousMdc
+ : (preferredOperationId != null ? preferredOperationId : RandomUtil.uuId()), previousMdc);
+ MDC.put(AuditApiConsts.MDC_OPERATION_ID, created.operationId);
+ TransactionSynchronizationManager.bindResource(RESOURCE_KEY, created);
+ TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
+ private TxAuditBuffer suspended;
+ @Override public void suspend() { // REQUIRES_NEW 鍐呭眰寮�濮嬶細TSM 涓� MDC 鍚屾鎸傝捣
+ suspended = (TxAuditBuffer) TransactionSynchronizationManager.unbindResource(RESOURCE_KEY);
+ // spec 搂4锛屾寜 (scopeOwned, previousMdc) 鍥涚粍鍚堣锛�
+ // (true , null) 褰㈡�佷笝/涓�/鎴� 鈫� 鎭㈠ operationId锛屽唴灞傛部鐢� 鈫愩�愭湰娆″敮涓�琚敼鍙樼殑缁勫悎銆�
+ // (true , X ) 鈫� 鎭㈠ operationId锛屼絾鐢� createBuffer 鐨勪笉鍙橀噺 X == operationId锛�
+ // 涓庤蛋绗簩鏀瓑浠凤紝鏃犺涓哄彉鍖�
+ // (false, X ) 褰㈡�佺敳 鈫� 鎭㈠ previousMdc = X锛屽唴灞傜収鏍锋部鐢紙浣滅敤鍩熷瓨鍦ㄤ絾涓嶇疆鏍囪锛�
+ // (false, null) 褰㈡�佷箼 鈫� 鎭㈠ null锛圡DC 娓呯┖锛夛紝鍐呭眰鍙︾敓鎴� id
+ // 鍚庝袱鏍奸�愬瓧淇濈暀 M1銆岀粓楠�#6锛氬彧瑙g粦璧勬簮涓嶅姩 MDC 鐨勮瘽锛屽唴灞備細鐪嬪埌澶栧眰 opId銆嶇殑鍘熻涓�
+ // 锛圫5 鏂█瀹堜箣锛夛紱绗竴鏍兼槸鏈**鏈夋剰瑕嗙洊**璇ョ粨璁衡�斺�旂粓楠�#6 鏄湪銆屼竴涓簨鍔′竴涓� id銆�
+ // 璇箟涓嬩綔鍑虹殑锛孧2 寮曞叆 beginOperation 鍚庤涔夋敼涓恒�屼竴娆$敤鎴锋搷浣滀竴涓� id銆嶃��
+ // 鏀瑰姩鍓嶅厛璇� spec 搂2 涓� createBuffer 澶勬爣鏄庣殑涓嶅彉閲忋��
+ restoreMdc(suspended.scopeOwned ? suspended.operationId : suspended.previousMdc);
+ }
+ @Override public void resume() {
+ TransactionSynchronizationManager.bindResource(RESOURCE_KEY, suspended);
+ MDC.put(AuditApiConsts.MDC_OPERATION_ID, suspended.operationId);
+ }
+ @Override public void afterCommit() {
+ if (created.events.isEmpty()) {
+ return; // beginOperation 寤轰簡缂撳啿浣嗘湰娆℃病鏈変簨浠讹紙濡傛敞瑙f柟娉曞唴鏃犲璁″姩浣滐級锛屼笉绌哄彂
+ }
+ publisher.publishAsync(new ArrayList<>(created.events)); // 鍥炴粴涓嶅彂
+ }
+ @Override public void afterCompletion(int status) {
+ if (TransactionSynchronizationManager.hasResource(RESOURCE_KEY)) {
+ TransactionSynchronizationManager.unbindResource(RESOURCE_KEY); // 闃叉硠婕�
+ }
+ restoreMdc(created.previousMdc); // 鎭㈠澶栧眰鍊� / 娓呯悊闃茬嚎绋嬫睜涓插彿
+ }
+ });
+ return created;
+ }
+
+ private static void restoreMdc(String previous) {
+ if (previous != null) {
+ MDC.put(AuditApiConsts.MDC_OPERATION_ID, previous);
+ } else {
+ MDC.remove(AuditApiConsts.MDC_OPERATION_ID);
+ }
+ }
+
+ /**
+ * 璇绘帴鍙o紙缁堥獙鍥涜疆鈶狅紝M1 鍙0鏄庝笉娑堣垂锛夛細杩斿洖褰撳墠浜嬪姟宸叉湁鐨� operationId锛�
+ * 鏃犳椿璺冪紦鍐茶繑鍥� null锛�**鏈柟娉曚笉瑙﹀彂鍒涘缓**锛堢粓楠屼簲杞憼锛歫avadoc 涓嶆壙璇鸿秴鍑轰唬鐮佽兘鍔涚殑璇箟锛夈��
+ * M2 璁捐濂戠害锛欯AuditLog aspect 涓嶅緱鑷鐢熸垚 operationId鈥斺�旇嫢闇�瑕� getOrCreate 璇箟锛�
+ * M2 鏃跺湪鏈被鏂板瀵瑰簲鏂规硶锛岀敱 holder 鍗曟簮鐢熸垚鍚庡啓 MDC 渚涙棫 BizLogAspect 璇诲彇锛�
+ * aspect 涓� holder 鍙屾簮鐢熸垚浼氱牬鍧� A/B 绮剧‘閰嶅銆�
+ */
+ public static String currentOperationId() {
+ TxAuditBuffer buffer = (TxAuditBuffer) TransactionSynchronizationManager.getResource(RESOURCE_KEY);
+ return buffer != null ? buffer.operationId : null;
+ }
+}
--
Gitblit v1.8.0