首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

J2EE Web 服務客戶端質量報告實戰(三):Payload 核心包設計與實現

     編輯:Java 相關知識

本篇深入剖析質量報告系統的核心共享組件——Payload 包,包含 ClientReport 數據模型、CurrentReport 事務邊界管理器、Serializer 序列化與隊列傳輸引擎,揭示輕量級、容錯設計精髓。

一、ClientReport:客戶端響應時間數據模型

public class ClientReport implements Serializable {
    public Date clientStartDateTime;    // 客戶端事務開始時間
    public Date serverStartDateTime;    // 服務端事務開始時間 (預留)
    public long clientElapsedMS;        // 核心指標:客戶端感知響應毫秒數
    public String type;                 // 事務類型特征 (如 "1 submit,check,gets")
    public String status;               // 完成狀態 (success/failed)
    public String transactionID;        // 服務端返回的事務標識
    public String clientID;             // 客戶端唯一標識 (UID 生成)

    // 默認構造器 (WSDL 要求)
    public ClientReport() {}
    // getter/setter 省略...
}

設計要點

  • clientElapsedMS:從 BeginTransaction() 到最後調用返回的牆鐘時間,反映用戶真實體驗
  • type:業務事務分類,支持不同類型性能對比
  • clientID:運行時生成 UID,區分同一客戶端多事務;生產環境應升級為全局唯一標識 (GUID)
  • serverStartDateTime:預留字段,未來可關聯服務端資源使用時間線

二、CurrentReport:事務邊界管理與報告生命週期

public class CurrentReport {
    public static UID ClientIdentifier = new UID(); // 客戶端標識
    public static ClientReport Report;              // 進行中事務報告
    public static ClientReport LastReport;          // 已完成事務報告 (待上傳)

    public void BeginTransaction() {
        Report = new ClientReport();
        Report.setClientID(ClientIdentifier.toString());
        Report.setClientStartDateTime(new Date());
    }

    public void CommitTransaction(String transactionID, String type, String status) {
        Report.setTransactionID(transactionID);
        Report.setStatus(status);
        Report.setType(type);
        long l1 = Report.getClientStartDateTime().getTime();
        long l2 = new Date().getTime();
        Report.setClientElapsedMS(l2 - l1); // 計算耗時
        LastReport = Report;                // 轉為待上傳狀態
        Report = null;                      // 清空當前事務
    }

    public static ClientReport getReport() {
        ClientReport last = LastReport;
        LastReport = null; // 取走即清空,確保單次上傳
        return last;
    }
    // setter 省略...
}

關鍵機制

  • 單線程假設:非線程安全,假設客戶端單線程執行事務
  • 雙緩衝模式:Report (構建中) ↔ LastReport (待上傳)
  • 一次性消費:getReport() 取走即清空,防止重複上傳
  • 時間測量:System.currentTimeMillis() 差值,簡單高效

三、Serializer:序列化、SOAP 附件綁定、JMS 隊列傳輸三合一

1. XML 序列化/反序列化 (基於 JavaBeans XMLEncoder/Decoder)

private static String ClientReportXML(ClientReport r) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    XMLEncoder sstream = new XMLEncoder(baos);
    sstream.writeObject(r);
    sstream.flush(); sstream.close();
    return baos.toString();
}

public static ClientReport ClientReportXML(String crXML) {
    ByteArrayInputStream bais = new ByteArrayInputStream(crXML.getBytes());
    XMLDecoder sstream = new XMLDecoder(bais);
    return (ClientReport) sstream.readObject();
}

2. 客戶端:附加報告至 SOAP 消息

public static void attachPendingReportToMessage(SOAPMessageContext smc) {
    try {
        ClientReport cr = CurrentReport.getReport();
        if (cr != null) {
            SOAPMessage mc = smc.getMessage();
            AttachmentPart ap = mc.createAttachmentPart(
                Serializer.ClientReportXML(cr), "text/plain");
            mc.addAttachmentPart(ap);
        }
    } catch (Exception e) {
        // 靜默吞噬:確保業務處理不受監控邏輯影響
    }
}

3. 服務端:剝離附件並入隊

public static void queueFirstAttachmentText(SOAPMessageContext smc) {
    try {
        SOAPMessage mc = smc.getMessage();
        Iterator attachments = mc.getAttachments();
        if (attachments.hasNext()) {
            AttachmentPart attachment = (AttachmentPart) attachments.next();
            String sattachment = attachment.getContent().toString();
            attachments.remove(); // 移除避免干擾業務解析
            queueReportXML(sattachment);
        }
    } catch (SOAPException e) { /* 記錄日誌 */ }
}

4. JMS 隊列發送引擎 (單例連接、同步發送)

// 靜態連接資源 (共享)
private static Context jndiContext = null;
private static QueueConnectionFactory queueConnectionFactory = null;
private static QueueConnection queueConnection = null;
private static QueueSession queueSession = null;
private static Queue queue = null;
private static QueueSender queueSender = null;
private static boolean connectionEstablished = false;

public static synchronized void queueReportXML(String clientReportXML) {
    TextMessage message = null;
    // 惰性初始化連接
    if (!connectionEstablished) {
        try {
            jndiContext = new InitialContext();
            queueConnectionFactory = (QueueConnectionFactory) jndiContext.lookup("jms/TestMDBFactory");
            queue = (Queue) jndiContext.lookup("jms/TestMDBQueue");
            queueConnection = queueConnectionFactory.createQueueConnection();
            queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
            queueSender = queueSession.createSender(queue);
            connectionEstablished = true;
        } catch (Exception e) { /* 記錄連接失敗 */ }
    }
    // 發送消息
    try {
        message = queueSession.createTextMessage();
        message.setText(clientReportXML);
        queueSender.send(message);
    } catch (JMSException e) { /* 記錄發送失敗 */ }
    catch (Exception e) { /* 兜底保護 */ }
}

核心設計原則

  1. 全異常吞噬:所有公共方法 try-catch 兜底,監控故障決不影響業務流程
  2. 同步發送:synchronized 保證單一連接多線程安全
  3. 惰性連接:首次發送時建立 JMS 連接,減少啟動開銷
  4. 假設唯一附件來源:若系統有其他附件用途,需擴展標識機制

四、調試驗證技巧

  • 設置 debug=true,調用 ((EDataGraph)dataGraph).getDataGraphResource().save(System.out, null) 輸出序列化 XML
  • Eclipse 調試器斷點觀察 Variables 面板:數據對象屬性、變更摘要內容

五、總結

Payload 包以極簡接口 (Begin/CommitTransaction、attach/queue) 實現全鏈路報告流轉:客戶端構建 → SOAP 附件攜帶 → 服務端剝離 → JMS 異步持久化。其零業務侵入、容錯優先、輕量級特性,使之成為服務質量監控的理想基礎設施。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved