Recently, I have been studying the work of Tomcat, the main way is to refer to the "How Tomcat Works" book and the source code of Tomcat 5.5.26.
The code structure of Tomcat is still relatively clear, and the annotations are quite complete. However, after all, the code is static, and it is difficult to fully understand the relationship between classes and classes, as well as the interaction of runtime objects.
If you can debug the boot, process requests and stops of Tomcat, and see every step of Tomcat, you can solve the problem.
So, another question comes out: How do I remotely debug tomcat using Eclipse?
On the Internet to check some information, related articles are still a lot of. I simply combed through the solutions and principles, and was familiar with Tomcat's startup scripts.
How can I debug the JVM remotely?
Debugging Tomcat remotely is essentially a remote debugging JVM. It is not necessary to understand the details of the operation of the JVM itself, but to understand the operational details of the application on the JVM.
In any case, we have to obtain internal information from the JVM runtime (such as viewing debug information) and control the JVM's running process (such as stepping) to achieve the purpose of debugging.
This thing depends on the debugger itself, certainly cannot be done. Otherwise, the security of the JVM is greatly compromised. Unless the JVM provides some kind of "backdoor", the debugger queries some run-time information and allows the debugger to send some control commands.
Have to sigh, the power of the JVM. Starting from J2se 1.4.2, it has been proposed and implemented JAVATM Platform Debugger Architecture, referred to as JPDA.
JPDA Introduction
As the name implies, JPDA defines a standard architecture for the debugger on the Java platform. The architecture consists of 3 main components: JVM TI, JDI, and jdwp.
The full name of the JVM ti is the Java Virtual machine Tool Interface, which defines the functions and the corresponding access interfaces that the JVM must provide in order to support debugging. These providers are provided in the native language, and are implemented by the JVM (such as Sun's hotspot VMs).
However, JVM Ti is just a series of functions provided by the JVM, how does the debugger (especially the remote debugger) invoke it? In fact, the direct client of the JVM ti is not a debugger, but a "JPDA back-end". This should be part of the JVM, and the Jdwp.dll (jdwp.so) library file can be found in the bin directory of the Sun JRE, which is the implementation of JPDA Back-end. As I understand it, JPDA Back-end provides a variety of access methods (shared memory, sockets), which receive the debugger's request and then invoke the JVM Ti interface.
The full name of JDI is the Java Debug Interface, which defines a high-level API to access the JVM Ti interface, provided in the Pure Java language and implemented by the JDK (found in the Tools.jar of the Sun JDK). The debugger uses JDI directly to implement debugging functionality. In contrast to the JPDA back-end, the role JDI implements is JPDA front-end.
The full name of JDWP is the Java Debug wire Protocol, which defines the binary format of communication information between JPDA front-end and Jpda back-end. The communication information here mainly includes two kinds: The debugger sends the request information to the JVM and the JVM sends the debugging information to the debugger.
To summarize, the debugger invokes the JDI implementation provided by the JDK (JPDA front-end), via the jdwp protocol , and the JVM's own JPDA back-end (jdwp.dll , jdwp.so, ...) for communication. JPDA back-end learns debug information or sends control commands by invoking the JVM Ti interface . JPDA Back-end then returns the debug information or command execution results to the debugger through the jdwp protocol .
How to enable JPDA
By default, the JVM does not have JPDA back-end enabled. The following parameters need to be loaded at the command line starting the JVM:
-xdebug-xrunjdwp:transport=dt_socket, Address=8000,server=y,suspend=y
-xdebug
Enabling Debugging Features
-xrunjdwp
Enables the JDWP implementation, which contains several sub-options:
Transport=dt_socket
JPDA the transfer method between front-end and Back-end. Dt_socket represents the use of socket transmissions.
address=8000
The JVM listens for requests on port 8000.
Server=y
Y indicates that the JVM being started is the debugger. If n, the JVM that starts is the debugger.
Suspend=y
Y indicates that the JVM that is started pauses waiting until the debugger is connected.
Suspend=y this option is important. If you want to debug from the beginning of Tomcat startup, you must set up suspend=y.
Tomcat's startup script
As soon as Tomcat starts, JPDA is enabled and can be debugged. Tomcat does not enable JPDA by default and requires us to turn it on manually.
The method of opening JPDA is also very simple, make some changes to the Tomcat startup script, add the command line parameter of starting JPDA, it is OK.
However, the Tomcat startup script is a bit more complicated than the simple "Java ...". Let's start with a simple comb.
In the bin directory of the Tomcat 5.5.26 release, there are more than n scripts, where the scripts related to Tomcat start-up are (for example, Windows):
Startup.bat//Start Tomcat
Shutdown.bat//Stop Tomcat
Catalina.bat//contains core logic for start/stop Tomcat
Both Startup.bat and Shutdown.bat have the ability to start and stop by calling Catalina.bat, so they both have very little code. The main logic is in the Catalina.bat.
Catalina.bat is a powerful script that, through parameters, can perform various actions, including debug run start stop version, and so on.
If we execute catalina.bat directly, we can see its usage description:
Startup.bat, is actually executes Catalina.bat start;shutdown.bat, actually is executes catalina.bat stop.
It is not difficult to guess, we can write a jdpa.bat, call Catalina.bat jpda start directly, you should be able to enable JPDA. We'll make a copy of the Startup.bat.
Call "%executable%" Start%cmd_line_args%
Modified into
Call "%executable%" JPDA start%cmd_line_args%
However,-xdebug-xrunjdwp:transport=dt_socket, address=8000,server=y,suspend=y, how are these option parameters passed to Catalina.bat?
Look at the note in front of Catalina.bat, the value of server is the default is Y,transport value is the value of the variable jpda_transport,address is the value of the variable jpda_address,suspend is a variable Jpda_ SUSPEND. If not explicitly copied, the values of these variables are DT_SHMEM jdbconn n by default (the default value means using shared memory as the transport). These default values are not what we need, ECLISEP remote debugging currently only supports socket transmission. Before calling Catalina.bat Jpda start, we set the appropriate values for these variables:
Set Jpda_transport=dt_socket
Set jpda_address=8000
Set Jpda_suspend=y
Call "%executable%" JPDA start%cmd_line_args%
Then, the direct execution of the JPDA.BAT,TOMCAT is run in JPDA adjustable mode:
As can be seen, Tomcat's JPDA uses socket transmission and listens on port 8000. Tomcat startup is paused, and only the debugger is connected to continue booting.
I have listed the full contents of Jpda.bat below, where the bold part, the code added on the Startup.bat basis:
@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 are needed to run
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 was needed to run
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
:d Onesetargs
Set Jpda_transport=dt_socket
Set jpda_address=8000
Set Jpda_suspend=y
Call "%executable%"JPDAStart%cmd_line_args%
: End
debugging Tomcat remotely in Eclipse
First, the Tomcat 5.5.26 source code is divided into container connectors Jasper Servletapi build five projects, imported into eclipse. Starting the related code is primarily in container, which opens the Debug Configurations dialog box for the current project.
Then create a "Remote Java application", Connection type Select "Standard (Socket Attach)", host fills in localhost (the host address where Tomcat resides), Port Fill 8000. Finally click "Apply" to save.
First make sure that you have executed jpda.bat,tomcat waiting for the debugger to connect, and then execute the above debug Configuration,eclipse to connect to Tomcat.
Tomcat starts with the main method of Bootstrap, I set a breakpoint at the first line of code, and Tomcat's boot stops at this line:
Next, let Tomcat continue, and we can see that the console output the boot information.