最近在开发java web application的时候,因为很多原因,无法对自己开发的项目在本地进行调试,常常需要进行远程调试,之前一直通过打logger的方式进行,每次都要重新部署,相当的痛苦,今天下午研究了以下,如果进行远程调试。
开发的web application是部署在tomcat上面的,那么问题就转化为如何调试tomcat。其实调试tomcat,本质上就是调试JVM。JVM的强大,从J2SE1.4.2开始,就实现了JPDA (Java Platform Debug Architecture)。
tomcat默认情况下,是没有启用jpda的,如果要启用,需要传入参数
-Xdebug -Xrunjdwp:transport=dt_socket, address=8000,server=y,suspend=y
那么问题是这些参数如何在tomcat启动的使用传入呢?这是时候,需要了解tomcat的启动脚本,在TOMCAT_HOME/bin
目录下,有三个脚本catalina.sh, startup.sh, 和 shutdown.sh。如果查看startup.sh和shutdown.sh,都是通过catalina.sh来启动的。脚本如下:
EXECUTABLE=catalina.sh
exec "$PRGDIR"/"$EXECUTABLE" start "$@"
于是,我们可以查看下catalina.sh的脚本是如何实现的。
# JPDA_TRANSPORT (Optional) JPDA transport used when the "jpda start"
# command is executed. The default is "dt_socket".
#
# JPDA_ADDRESS (Optional) Java runtime options used when the "jpda start"
# command is executed. The default is 8000.
#
# JPDA_SUSPEND (Optional) Java runtime options used when the "jpda start"
# command is executed. Specifies whether JVM should suspend
# execution immediately after startup. Default is "n".
#
# JPDA_OPTS (Optional) Java runtime options used when the "jpda start"
# command is executed. If used, JPDA_TRANSPORT, JPDA_ADDRESS,
# and JPDA_SUSPEND are ignored. Thus, all required jpda
# options MUST be specified. The default is:
#
# -agentlib:jdwp=transport=$JPDA_TRANSPORT,
# address=$JPDA_ADDRESS,server=y,suspend=$JPDA_SUSPEND
if [ "$1" = "jpda" ] ; then
if [ -z "$JPDA_TRANSPORT" ]; then
JPDA_TRANSPORT="dt_socket"
fi
if [ -z "$JPDA_ADDRESS" ]; then
JPDA_ADDRESS="8000"
fi
if [ -z "$JPDA_SUSPEND" ]; then
JPDA_SUSPEND="n"
fi
if [ -z "$JPDA_OPTS" ]; then
JPDA_OPTS="-agentlib:jdwp=transport=$JPDA_TRANSPORT,address=$JPDA_ADDRESS,server=y,suspend=$JPDA_SUSPEND"
fi
CATALINA_OPTS="$CATALINA_OPTS $JPDA_OPTS"
shift
fi
通过这个代码,我们可以看出,其实要启动jpda, 最主要的是要对JPDA_SUSPEND的值进行设置,由N改为Y。
借鉴start.sh的启动,在linux下,我们可以自己创建一个jpda.sh的脚本,用来启动开启debug模式的tomcat,具体脚本如下,黑体为修改部分。
os400=false
darwin=false
case "`uname`" in
CYGWIN*) cygwin=true;;
OS400*) os400=true;;
Darwin*) darwin=true;;
esac
# resolve links - $0 may be a softlink
PRG="$0"
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`/"$link"
fi
done
PRGDIR=`dirname "$PRG"`
EXECUTABLE=catalina.sh
# Check that target executable exists
if $os400; then
# -x will Only work on the os400 if the files are:
# 1. owned by the user
# 2. owned by the PRIMARY group of the user
# this will not work if the user belongs in secondary groups
eval
else
if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then
echo "Cannot find $PRGDIR/$EXECUTABLE"
echo "The file is absent or does not have execute permission"
echo "This file is needed to run this program"
exit 1
fi
fi
export JPDA_SUSPEND=y
exec "$PRGDIR"/"$EXECUTABLE" jpda start "$@"
在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“保存。
首先确保已经执行了jpda.bat,Tomcat正在等待调试器连接;然后执行上述的Debug Configuration,Eclipse就可以连上Tomcat。
Tomcat的启动是从Bootstrap的main方法开始,我在第一行代码处设置了断点,Tomcat的启动就停在了这一行:
接着,让Tomcat继续执行,我们可以看到,控制台输出了启动信息。
-----------------------------------------------------
Silence, the way to avoid many problems;
Smile, the way to solve many problems;