1. 程式人生 > >Tomcat debug模式啟動

Tomcat debug模式啟動

在%CATALINA_HOME%\bin\startup.bat中新增以下任意一行配置: 
SET JAVA_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n 

SET CATALINA_OPTS=-server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8787 


啟動tomcat後,在控制檯顯示以下內容表示配置成功: 

Listening for transport dt_socket at address: 8787

JPDA簡介

顧名思義,JPDA為Java平臺上的偵錯程式定義了一個標準的體系結構。該體系結構包括3個主要組成部分:JVM TI、JDI和JDWP。

JVM TI的全稱是Java Virtual Machine Tool Interface,它定義了JVM為了支援除錯而必須提供的功能及相應的訪問介面。這些訪問介面是以本地語言的形式提供的,由JVM(比如Sun公司的HotSpot VM)負責實現。

不過,JVM TI只是JVM提供的一系列函式,偵錯程式(特別是遠端的偵錯程式)如何呼叫呢?其實啊,JVM TI的直接客戶端並不是偵錯程式,而是一個稱為“JPDA back-end”的東東。這個東東應該是屬於JVM的一部分,在SUN JRE的bin目錄下可以找到jdwp.dll(jdwp.so)的庫檔案,這就是JPDA back-end的實現。按我理解,JPDA back-end提供了各種訪問方式(共享記憶體,Socket),通過這些方式接收偵錯程式的請求,然後呼叫JVM TI介面。

JDI的全稱是Java Debug Interface,它定義了訪問JVM TI介面的高層API,以純Java語言提供,由JDK實現(在Sun JDK的tools.jar可以找到)。偵錯程式直接使用JDI來實現除錯的功能。與JPDA back-end相對應,JDI實現的角色就是JPDA front-end。

JDWP的全稱是Java Debug Wire Protocol,它定義了JPDA front-end和JPDA back-end之間通訊資訊的二進位制格式。這裡的通訊資訊主要包括兩種:偵錯程式傳送給JVM的請求資訊和JVM傳送給偵錯程式的除錯資訊。

總結一下,偵錯程式 呼叫JDK提供的JDI實現 (JPDA front-end),經由JDWP協議 ,和JVM自帶的JPDA back-end(jdwp.dll, jdwp.so, ...)進行通訊。JPDA back-end 通過呼叫JVM TI介面 ,從而獲知除錯資訊,或傳送控制命令。然後,JPDA back-end 將除錯資訊或命令執行結果,通過JDWP協議 ,返回給偵錯程式 。

如何啟用JPDA

預設情況下,JVM並沒有啟用JPDA back-end。需要在啟動JVM的命令列載入以下引數:

-Xdebug

-Xrunjdwp:transport=dt_socket, address=8000,server=y,suspend=y

-Xdebug

啟用除錯特性

-Xrunjdwp

啟用JDWP實現,它包含若干子選項:

transport=dt_socket

JPDA front-end和back-end之間的傳輸方法。dt_socket表示使用套接字傳輸。

address=8000

JVM在8000埠上監聽請求。

server=y

y表示啟動的JVM是被除錯者。如果為n,則表示啟動的JVM是偵錯程式。

suspend=y

y表示啟動的JVM會暫停等待,直到偵錯程式連線上。

suspend=y這個選項很重要。如果你想從Tomcat啟動的一開始就進行除錯,那麼就必須設定suspend=y。

Tomcat的啟動指令碼

只要Tomcat啟動時,啟用了JPDA,那麼就可以被除錯。而Tomcat預設是不啟用JPDA的,需要我們手動開啟。

開啟JPDA的方法也很簡單,對Tomcat的啟動指令碼做點修改,把啟動JPDA的命令列引數新增進去,就可以了。

不過Tomcat啟動指令碼還是有點複雜的,並不是簡單的”java ...“。我們先簡單的梳理一下。

在Tomcat 5.5.26發行版的bin目錄下,有N多指令碼,其中與Tomcat啟停有關的指令碼是(以Windows為例):

startup.bat        //啟動Tomcat

shutdown.bat   //停止Tomcat

catalina.bat       //包含啟動/停止Tomcat的核心邏輯

startup.bat和shutdown.bat都是通過呼叫catalina.bat來實現啟動和停止的功能,因此他倆的程式碼都很少。主要的邏輯都在catalina.bat中。

catalina.bat是個強大的指令碼,通過引數,可以執行各種動作,包括debug run start stop version等。

如果我們直接執行catalina.bat,就可以看到它的用法說明:

直接執行catalina.bat時的輸出

startup.bat,其實就是執行catalina.bat start;shutdown.bat,其實就是執行catalina.bat stop。

不難猜到,我們可以寫一個jdpa.bat,直接呼叫catalina.bat jpda start,應該就可以啟用JPDA。我們拷貝一份startup.bat,把下面這行

call "%EXECUTABLE%" start %CMD_LINE_ARGS%

修改成

call "%EXECUTABLE%" jpda start %CMD_LINE_ARGS%

不過,-Xdebug -Xrunjdwp:transport=dt_socket, address=8000,server=y,suspend=y,這些選項引數怎麼傳遞給catalina.bat呢?

看看catalina.bat前面的註釋,server的值預設就是y,transport的值是變數JPDA_TRANSPORT,address的值是變數JPDA_ADDRESS,suspend的值是變數JPDA_SUSPEND 。如果沒有顯式地複製,這些變數的值預設是dt_shmem jdbconn n(預設值表示使用共享記憶體作為傳輸方式)。這些預設值不是我們需要的,Eclisep的遠端除錯目前只支援套接字傳輸。在呼叫catalina.bat jpda start之前,我們給這些變數設定恰當的值:

set JPDA_TRANSPORT=dt_socket
set JPDA_ADDRESS=8000
set JPDA_SUSPEND=y

call "%EXECUTABLE%" jpda start %CMD_LINE_ARGS%

然後,直接執行jpda.bat,Tomcat就執行在JPDA可調式模式下:

啟用JPDA的Tomcat

從上圖可以看出,Tomcat的JPDA使用套接字傳輸,監聽在8000埠。Tomcat的啟動已經暫停,只有偵錯程式連線上來,才會繼續啟動。

我把jpda.bat的完整內容列在下面,其中黑體部分,在startup.bat基礎上新增的程式碼:

@echo off
if "%OS%" == "Windows_NT" setlocal
rem ---------------------------------------------------------------------------
rem Jpda script for the CATALINA Server
rem
rem $Id: jpda.bat 302918 2004-05-27 18:25:11Z yoavs $
rem ---------------------------------------------------------------------------

rem Guess CATALINA_HOME if not defined
set CURRENT_DIR=%cd%
if not "%CATALINA_HOME%" == "" goto gotHome
set CATALINA_HOME=%CURRENT_DIR%
if exist "%CATALINA_HOME%/bin/catalina.bat" goto okHome
cd ..
set CATALINA_HOME=%cd%
cd %CURRENT_DIR%
:gotHome
if exist "%CATALINA_HOME%/bin/catalina.bat" goto okHome
echo The CATALINA_HOME environment variable is not defined correctly
echo This environment variable is needed to run this program
goto end
:okHome

set EXECUTABLE=%CATALINA_HOME%/bin/catalina.bat

rem Check that target executable exists
if exist "%EXECUTABLE%" goto okExec
echo Cannot find %EXECUTABLE%
echo This file is needed to run this program
goto end
:okExec

rem Get remaining unshifted command line arguments and save them in the
set CMD_LINE_ARGS=
:setArgs
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto setArgs
:doneSetArgs

set JPDA_TRANSPORT=dt_socket
set JPDA_ADDRESS=8000
set JPDA_SUSPEND=y
 

call "%EXECUTABLE%" jpda start %CMD_LINE_ARGS%

:end

在Eclipse中遠端除錯Tomcat

首先將Tomcat 5.5.26的原始碼分為container connectors jasper servletapi build五個專案,匯入到Eclipse中。啟動相關的程式碼主要在container中,就以它為當前專案,開啟”Debug Configurations“對話方塊。

然後建立一個”Remote Java Application“,Connection Type選擇”Standard (Socket Attach)“,Host填寫localhost(Tomcat所在的主機地址),Port填寫8000。最後點選”Apply“儲存。

Eclipse的Debug Configurations對話方塊中配置遠端除錯

首先確保已經執行了jpda.bat,Tomcat正在等待偵錯程式連線;然後執行上述的Debug Configuration,Eclipse就可以連上Tomcat。

Tomcat的啟動是從Bootstrap的main方法開始,我在第一行程式碼處設定了斷點,Tomcat的啟動就停在了這一行:

斷點除錯Tomcat的啟動過程

接著,讓Tomcat繼續執行,我們可以看到,控制檯輸出了啟動資訊。

Tomcat在JPDA模式下繼續啟動