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

AOP@Work: AspectJ 企業級效能監控實戰 (二) — 擴展 Glassbox Inspector 支援框架、Web Service 與生產部署

     編輯:Java 相關知識

前言:從核心監控到生產就緒

第一部分建立了基於 AspectJ + JMX 的 `Glassbox Inspector` 核心:監控 Servlet 請求、JDBC 連線/Statement、巢狀統計、JMX 公開。第二部分將其擴展為**企業級監控基礎設施**:支援 Struts/Spring MVC 控制器、Web Service (Axis)、多應用程式隔離、錯誤追蹤、執行時動態開關、錯誤隔離層、Load-Time Weaving (LTW) 部署、效能與記憶體基準測試。

可重用操作監控器:抽象巢狀請求統計

`AbstractOperationMonitor` 延伸 `AbstractRequestMonitor`,核心改進:

  • `OperationRequestContext`:攜帶 `controller` 參考,`lookupStats()` 依父子關係決定統計物件 — **巢狀操作共享父層統計容器** (如 `DispatchAction` 分派多方法、Spring `MultiActionController`)。
  • `getTopLevelStats(key)`:工廠模式建立頂層 `OperationStats`,鍵值可為類別或 `類別+方法名`。
  • `getContextName(controller)`:模板方法,**支援單一伺服器多 Web 應用** — 由 ServletContext 取得應用名稱,統計鍵值前綴 `application=MyApp`。

框架專用監控器:Struts 與 Spring MVC

核心模板切點 (在 `AbstractOperationMonitor`):

  • `classControllerExec(Object controller)`:類層級控制器 (如 Struts `Action.execute`、Servlet `doGet`)。
  • `methodSignatureControllerExec(Object controller)`:方法簽名層級 (如 `DispatchAction` 子類多方法、Spring `MultiActionController` 多 handler)。

StrutsMonitor (支援 Struts 1.0 `perform` / 1.1 `execute`)

public aspect StrutsMonitor extends AbstractOperationMonitor {
    public interface NotMonitoredAction {} // 標記介面排除特定 Action
    public pointcut actionMethodExec() :
        execution(public ActionForward Action+.*(ActionMapping, ActionForm, ServletRequest+, ServletResponse+))
        && !within(NotMonitoredAction);
    public pointcut rootActionExec() :
        actionMethodExec() && (execution(* Action.execute(..)) || execution(* Action.perform(..)));
    protected pointcut classControllerExec(Object controller) : rootActionExec() && this(controller);
    protected pointcut dispatchActionMethodExec() : actionMethodExec() && execution(* DispatchAction+.*(..));
    protected pointcut methodSignatureControllerExec(Object controller) : dispatchActionMethodExec() && this(controller);
}
  • 正常 `Action` 以類為鍵統計 (`classControllerExec`)。
  • `DispatchAction` 子類各方法以 `類+方法名` 為鍵統計 (`methodSignatureControllerExec`)。
  • 可移植切點技巧:`this(controller)` 綁定 `Object` 而非 `Action`,**避免織入時需載入 Struts 類別**,支援多版本共存。

SpringMvcMonitor

public aspect SpringMvcMonitor extends AbstractOperationMonitor {
    public interface NotMonitoredController {}
    public pointcut springControllerExec() :
        execution(public ModelAndView Controller+.*(HttpServletRequest, HttpServletResponse))
        && !within(NotMonitoredController+);
    protected pointcut classControllerExec(Object controller) :
        springControllerExec() && execution(* handleRequest(..)) && this(controller);
    protected pointcut methodSignatureControllerExec(Object controller) :
        springControllerExec() && execution(* MultiActionController+.*(..)) && this(controller);
}
  • 所有 `Controller` 的 `handleRequest` 為類層級統計。
  • `MultiActionController` 子類各 handler 方法為方法層級統計 (如 `welcomeHandler`、`ownerHandler` 分開統計)。

可移植切點設計原則

  1. 靜態解析上下文 (類型模式、簽名) 使用具體類名 (如 `Action+`),**不觸發類別載入**。
  2. 動態上下文 (`this`、`target`、`args`) 綁定 `Object` 或介面,**避免織入器需解析具體實作類**。
  3. Advice 本體若需呼叫 API 方法,用反射檢查版本差異;`proceed()` 由 AspectJ 自動處理多版本相容。
  4. 不主動觸發可選類載入 (如 `WeakIdentityHashMap` 儲存連線),保持監控代碼輕量、不干擾應用類別載入順序。

JMX 命名策略升級:巢狀統計的層次化顯示

統計物件命名格式:

application=Spring Petclinic,operation=org.springframework.samples.petclinic.web.ClinicController,database=jdbc:hsqldb:hsql://localhost:9001,statement=SELECT id,name from types ORDER BY name
  • `StatsJmxManagement` 引入 `StatsJmxNameStrategy` 介面,預設 `GuiFriendlyStatsJmxNameStrategy` 遞迴組合父層名稱。
  • JConsole 等 JMX Client 依鍵值逗號分隔自動構建樹狀視圖 (見圖 1)。
  • 可選 `CanonicalStatsJmxNameStrategy` 符合 JMX ObjectName 標準,但工具支援度較低。

完整監控基礎設施 JConsole 快照

圖 1:JConsole 顯示多應用、巢狀操作、資料庫、Web Service 統計樹

Web Service 監控:JAX-RPC / Axis 遠端呼叫

`RemoteCallMonitor` 延伸 `AbstractResourceMonitor`:

public pointcut remoteProxyCall(Object recipient) :
    call(public * Remote+.*(..) throws RemoteException) && target(recipient) && !within(glassbox.inspector..*);
Object around(final Object recipient) : remoteProxyCall(recipient) { ... }
  • 攔截所有 `java.rmi.Remote` 介面方法呼叫 (含 JAX-RPC Proxy、RMI Stub)。
  • 統計鍵:`jaxrpc:fully.qualified.InterfaceName.methodName`。
  • 整合應用上下文:將外部服務呼叫納入請求巢狀統計,關聯 DB/邏輯耗時,**快速定位分散式延遲根因**。

錯誤監控與失敗偵測策略

  1. 記錄拋出 Throwable 的請求:`AbstractRequestMonitor` 新增 `after() throwing` advice,預設視所有 Throwable 為失敗。
  2. 可配置 `FailureDetectionStrategy`:介面 `isFailure(Throwable, StaticPart)`。預設 `true`。可換裝策略忽略業務性異常 (如 `ConcurrencyFailureException`、`DataIntegrityViolationException`)。
  3. 異常轉換模式:`DataAccessErrorHandling` 切面 `declare soft: SQLException` + Spring `SQLExceptionTranslator` 轉為 unchecked 有意義異常,`declare precedence` 確保轉換優於監控記錄。
  4. Web 層常見錯誤偵測 (ServletMonitor):
    • `sendError(int sc)` → 記錄 HTTP 錯誤碼
    • `PageContext.handlePageException(Throwable)` → 記錄 JSP 錯誤頁轉發

擴充切面的可擴充性模式

  • 抽象切點定義範圍 (`scope()`)
  • 空切點預設實作,子切面覆蓋啟用 (`classControllerExec` 模板)
  • 標記介面 / Java 5 註解 精確控制套用範圍
  • 執行時行為開關 (`if(aspectOf().isEnabled())`)

錯誤隔離層:監控代碼絕不拖垮業務

`ErrorHandling` 切面攔截監控代碼內所有 `Throwable`:

  • 範圍:`glassbox.inspector..*` 內 `before`/`after` advice、helper 方法、`execute`/`doExecute` 內呼叫。**排除 `around` advice 的 `proceed()` 拋出的異常 (讓業務異常正常傳播)。**
  • 機制:`around() : handlingScope() { try { proceed(); } catch (Throwable) { log & swallow; return null; } }`
  • `declare soft` 處理 checked exception。
  • 弱引用 `WeakHashMap` 記錄錯誤計數,防記憶體洩漏。
  • 開銷極低,生產環境可安心啟用。

執行時動態控制:JMX 管理監控器開關

  • `AbstractRequestMonitor` 引入 `enabled` boolean 屬性 + `monitorEnabled()` 切點結合 `if(aspectOf().isEnabled())`。
  • `MonitorJmxManagement` 透過 `declare parents` 讓所有監控器實作 `RequestMonitorMBean` (含 `isEnabled`/`setEnabled`)。
  • JConsole 即時啟用/停用特定監控器 (見圖 2),**無需重啟應用**。
  • 高開銷監控器 (如完整 SQL 參數記錄) 平時關閉,事故時動態開啟。

JConsole 動態控制監控器

圖 2:JConsole 執行時啟用/停用 JDBC Statement 監控

生產部署:Load-Time Weaving (LTW) 配置實戰

編譯期織入需處理第三方 JAR 依賴複雜。**LTW 僅需:獨立編譯監控切面 → 打包 `glassboxInspector.jar` → `META-INF/aop.xml` 定義織入規則 → 啟動參數 `-javaagent:aspectjweaver.jar`。**

aop.xml 範例

<aspectj>
  <weaver>
    <exclude within="org.springframework.jmx..*"/> <!-- 排除 Spring JMX 內部,加速啟動 -->
    <exclude within="glassbox.inspector..*"/> <!-- 避免自我織入 -->
  </weaver>
  <aspects>
    <aspect name="glassbox.inspector.monitor.operation.StrutsMonitor"/>
    <aspect name="glassbox.inspector.monitor.operation.SpringMvcMonitor"/>
    <aspect name="glassbox.inspector.monitor.resource.JdbcStatementMonitor"/>
    <concrete-aspect name="glassbox.inspector.monitor.operation.CustomMvcMonitor"
        extends="glassbox.inspector.monitor.operation.TemplOperationMonitor">
      <pointcut name="classControllerExecTarget"
          expression="execution(* com.ibatis.struts.BaseBean..*(..)) && cflow(execution(* com.ibatis.struts.BeanAction.execute(..)))"/>
    </concrete-aspect>
  </aspects>
</aspectj>
  • `concrete-aspect`:XML 定義具體切點,**無需編譯代碼**即可擴展監控自定義框架 (如 iBatis Struts 基礎類)。
  • 移除 `` 即停用該監控器,降低開銷 (需重啟)。

Tomcat 5.5 啟用 LTW

# Windows setclasspath.bat
set JAVA_OPTS=-javaagent:%CATALINA_HOME%\common\lib\aspectjweaver.jar -Xmx256m
# Linux setclasspath.sh 同理
  • 將 `glassboxInspector.jar` + 依賴放入 Tomcat `shared/lib`:**全伺服器所有 WebApp 自動受監控**,無需修改各應用 `WEB-INF/lib`。
  • 或放入 `common/lib` 監控 Tomcat 內部 (通常不必要,增加啟動時間)。

效能與記憶體基準測試 (Windows XP, JRockIt 1.5, Tomcat 5.5.9)

狀態平均端到端回應時間 (ms)伺服器啟動時間 (s)啟動進程記憶體 (MB)
監控啟用 + LTW20 (+10ms)15135 (+100%)
監控部署但執行時停用1015 (含織入)130
未部署監控10565
  • **穩態開銷極低**:50 併發用戶下平均延遲仅 +10ms。
  • **啟動代價**:LTW 織入增加 ~10s 啟動時間,記憶體翻倍 (AspectJ 織入器、切面類別、WeakMap 等)。
  • **優化方向**:`java.util.concurrent` 替換同步鎖、Alpha 版本優化空間大、AspectJ LTW 持續改進中。

未來路線圖與貢獻邀請

  • 更豐富上下文捕獲 (堆疊追蹤、參數值、異常時快照)
  • JMS、EJB、XML 處理監控
  • 分散式追蹤 (跨叢集關聯)
  • Java 5 管理資訊 (CPU 時間、執行緒統計)
  • 應用伺服器 JMX 整合 (執行緒池、連線池)
  • 歷史趨勢持久化、報警、統計匯總圖表
  • 適應性參數發現、高層框架資源監控 (Hibernate、JPA、JAX-WS)
  • 取樣機制控制資料量、非 Servlet 錯誤監控 (404)、業務事件監控 (購物車放棄)

完整源碼下載:developerWorks。歡迎加入 Glassbox Inspector 開源社群,貢獻代碼、回報問題、拓展新方向。

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