在Intellij下远程调试tomcat应用(含tomcat源码调试)

环境

服务器:

  • 操作系统:centos6
  • jdk:1.7
  • tomcat:8.5.9

本地:

  • 操作系统:mac osx 10.11.6
  • jdk:1.7
  • intellij:2016.2
  • tomcat:8.5.9(本地也需要下载tomcat)

应用调试步骤

java应用远程调试都是基于jpda体系,所以我们需要将tomcat通过jpda的方式启动,即可对tomcat进行远程调试。

一、服务端tomcat配置

假设服务端tomcat所在目录为:/etc/tomcat/。对于tomcat来说,所有运行相关的脚本都位于bin文件夹下,而catalina.sh是启动tomcat最为核心的脚本。为了使得tomcat能够支持远程调试,我们需要设置jpda相关的参数,但是tomcat官方建议我们不要直接修改catalina.sh里面定义的参数,而是将自定义的参数值设置在setenv.sh脚本中,证据如下:

# Environment Variable Prerequisites
#
#   Do not set the variables in this script. Instead put them into a script
#   setenv.sh in CATALINA_BASE/bin to keep your customizations separate.

tomcat里定义的jpda参数有:

  • JPDA_TRANSPORT:设置jpda传输方式,默认为dt_socket,此参数一般保持默认值即可。
  • JPDA_ADDRESS:服务端jpda监听的地址和端口,默认为localhost:8000,即本地的8000端口。此参数需根据实际情况进行修改。比如在本文场景中,我们需要远程调试tomcat,所以不能监听在本地,否则外网无法访问。
  • JPDA_SUSPEND:设置应用程序是否一启动就挂起,等待客户端调试器连接,默认为"n"也就是不挂起,若需要设置为挂起则修改为"y"。
  • JPDA_OPTS:若用户设置了该参数,则脚本执行时会忽略上述三个参数,直接拿JPDA_OPTS的值作为jpda的启动参数。

默认情况下,tomcat的jpda启动配置为:

-agentlib:jdwp=transport=dt_socket,address=localhost:8000,server=y,suspend=n

我们需要根据自己的实际情况设置合适的参数,具体设置的步骤如下:

  1. 在bin文件夹下新建setenv.sh并编辑:

    # cd /etc/tomcat/bin
    # vim setenv.sh
    
  2. 设置JPDA_ADDRESS的值为0.0.0.0:8000

    JPDA_ADDRESS=0.0.0.0:8000
    

    保存退出。

  3. 以jpda的方式启动tomcat:

    # ./catalina.sh jpda start
    

此时tomcat已经以jpda的方式启动,并且向外网开放了8000端口等待客户端发送调试命令。

二、Intellij配置

接下来我们需要配置intellij,具体步骤如下:

  1. 首先打开Run/Debug Configuration窗口:

  2. 点击左上角的➕号,添加一个Remote Tomcat:

  3. 填写Server配置项,需要配置的有配置名称、本地tomcat路径以及tomcat所在的host和开放的端口:

  4. 配置debug所需的参数。在本例中,由于我们在服务端的tomcat配置的是dt_socket,端口为8000,所以在这里我们也需要配置为socket和8000端口:

  5. 选择刚才的配置(比如在本例中为开发机),然后点击debug图标,打断点,开始远程调试:

调试tomcat源码

在某些情况下,我们需要调试tomcat自己的运行情况,比如为何应用里配置的listener没有加载成功,或者想研究tomcat的应用机制,这个时候,我们就需要直接调试tomcat的源码。

一、下载源码

俗话说,巧妇难为无米之炊,我们首先需要下载tomcat的源码。在本例中,我们tomcat的版本为8.5.9,下载地址请点击。下载成功后解压,我们假设源码目录位于:~/tomcat/

二、导入源码

我们需要将源码导入到intellij中,为接下来的调试打好基础。

  1. 下载下来的tomcat是一个ant工程,为了方便,我们首先将其转化为一个maven工程,这样我们就不需要关心依赖包的下载问题。我们在源码目录下新建pom.xml文件,pom的内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>Tomcat8.0</artifactId>
        <name>Tomcat8.0</name>
        <version>8.0</version>
    
        <build>
            <finalName>Tomcat8.0</finalName>
            <sourceDirectory>java</sourceDirectory>
            <testSourceDirectory>test</testSourceDirectory>
            <resources>
                <resource>
                    <directory>java</directory>
                </resource>
            </resources>
            <testResources>
                <testResource>
                    <directory>test</directory>
                </testResource>
            </testResources>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.3</version>
    
                    <configuration>
                        <encoding>UTF-8</encoding>
                        <source>1.7</source>
                        <target>1.7</target>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.11</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>ant</groupId>
                <artifactId>ant</artifactId>
                <version>1.7.0</version>
            </dependency>
            <dependency>
                <groupId>wsdl4j</groupId>
                <artifactId>wsdl4j</artifactId>
                <version>1.6.2</version>
            </dependency>
            <dependency>
                <groupId>javax.xml</groupId>
                <artifactId>jaxrpc</artifactId>
                <version>1.1</version>
            </dependency>
            <dependency>
                <groupId>org.eclipse.jdt.core.compiler</groupId>
                <artifactId>ecj</artifactId>
                <version>4.5</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.easymock/easymock -->
            <dependency>
                <groupId>org.easymock</groupId>
                <artifactId>easymock</artifactId>
                <version>3.2</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </project>
    
  2. 然后我们将源码导入到intellij中:

    在弹出来的对话框中选择刚才源码所在的目录,并且作为Maven工程导入,即可导入成功。

  3. 为了避免待会执行test时出现问题,我们需要删除test/util/TestCookieFilter.java文件。

三、配置远程调试

配置步骤与第二部分介绍的配置步骤相同。唯一需要注意的是,服务端的tomcat在配置jpda参数时,可以将JPDA_SUSPEND设置为y,这样tomcat启动之后不会执行任何代码,而是挂起,直到客户端连上来后才会继续执行。

其他

如果存在服务端jpda已经启动,但是客户端无法连接的情况,请检查防火墙。

参考资料

  1. Tomcat8源码学习之导入到IDEA

推荐阅读更多精彩内容