Debugging Spring Applications – 调试Spring应用程序

最后修改: 2018年 12月 23日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

Debugging is one of the most important tools for writing software.

调试是编写软件的最重要工具之一。

In this tutorial, we’ll review some of the ways in which we can debug Spring applications.

在本教程中,我们将回顾一些可以调试Spring应用程序的方法。

We’ll also demonstrate how Spring Boot, traditional application servers, and IDEs simplify this.

我们还将展示Spring Boot、传统应用服务器和IDE是如何简化的。

2. Java Debug Args

2.Java Debug Args

First, let’s look at what Java gives us out of the box.

首先,让我们看看Java给我们带来了什么。

By default, the JVM doesn’t enable debugging. This is because debugging creates additional overhead inside the JVM. It can also be a security concern for applications that are publicly accessible.

默认情况下,JVM不启用调试功能。这是因为调试会在JVM内部产生额外的开销。对于可公开访问的应用程序来说,这也可能是一个安全问题。

Therefore, debugging should only be performed during development, and never on production systems.

因此,调试只应在开发期间进行,而不应在生产系统上进行。

Before we can attach a debugger, we must first configure the JVM to allow debugging. We’ll do this by setting a command line argument for the JVM:

在连接调试器之前,我们必须首先配置JVM以允许调试。我们将通过为JVM设置一个命令行参数来做到这一点。

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

Let’s break down what each of these values means:

让我们来分析一下这些价值中的每一个意味着什么。

-agentlib:jdwp

-agentlib:jdwp

This enables the Java Debug Wire Protocol (JDWP) agent inside the JVM. This is the main command line argument that enables debugging.

这将启用JVM内部的Java Debug Wire Protocol(JDWP)代理。这是启用调试的主要命令行参数

transport=dt_socket

transport=dt_socket

This uses a network socket for debug connections. Other options include Unix sockets and shared memory.

这使用一个网络套接字来进行调试连接。其他选项包括Unix套接字和共享内存。

server=y

server=y

This listens for incoming debugger connections. When set to n, the process will try to connect to a debugger instead of waiting for incoming connections. Additional arguments are required when this is set to n.

这是对传入的调试器连接的监听。当设置为n时,进程将尝试连接到一个调试器,而不是等待进入的连接。当它被设置为n时,需要额外的参数。

suspend=n

suspend=n

This means don’t wait for a debug connection at startup. The application will start and run normally until a debugger is attached. When set to y, the process won’t start until a debugger is attached.

这意味着在启动时不要等待调试连接。应用程序将正常启动和运行,直到调试器被连接。当设置为y时,程序不会启动,直到调试器被连接。

address=8000

address=8000

This is the network port that the JVM will listen on for debug connections.

这是JVM为调试连接所监听的网络端口。

The values above are standard and will work for most use cases and operating systems. The JPDA connection guide covers all the possible values in more detail.

上面的值是标准值,对大多数使用情况和操作系统都适用。JPDA连接指南更详细地介绍了所有可能的值。

2.1. Binding Address on JDK9+

2.1.JDK9+上的绑定地址

On JDK8 and below, setting the address property to port number only (address=8000 in the example above) means that the JVM listens on all available IP addresses. Therefore, remote connections are available out of the box.

在JDK8及以下版本中,将address属性仅设置为端口号(上面例子中的address=8000)意味着JVM监听所有可用的IP地址。因此,远程连接是开箱即用的。

This has changed in JDK9+ due to security reasons. Currently, the default setup allows localhost connections only.

由于安全原因,这在JDK9+中有所改变。目前,默认设置只允许本地主机连接。

This means that if we want to make remote connections available, we need to either prefix the port number with the hostname, address=myhost:8000, or use an asterisk to listen on all available IP addresses, address=*:8000.

这意味着,如果我们想使远程连接可用,我们需要在端口号前加上主机名,address=myhost:8000,或者使用星号来监听所有可用的IP地址,address=*:8000。

3. Spring Boot Applications

3.Spring Boot应用

There are several ways to start Spring Boot applications. The simplest way is from the command line using the java command with the -jar option.

有几种方法可以启动 Spring Boot 应用程序。最简单的方法是在命令行中使用带有-jar选项的java命令。

To enable debugging, we simply add the debug argument using the -D option:

要启用调试,我们只需使用-D选项添加调试参数。

java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000 -jar myapp.jar

With Maven, we can use the provided run goal to start our application with debugging enabled:

利用Maven,我们可以使用提供的run目标,在启用调试的情况下启动我们的应用程序。

mvn spring-boot:run -Dspring-boot.run.jvmArguments="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000"

Similarly, with Gradle, we can use the bootRun task. First, we must update the build.gradle file to ensure Gradle passes command line arguments to the JVM:

同样地,对于Gradle,我们可以使用bootRun任务。首先,我们必须更新build.gradle文件以确保Gradle将命令行参数传递给JVM。

bootRun {
   systemProperties = System.properties
}

Now we can execute the bootRun task:

现在我们可以执行bootRun任务。

gradle bootRun -Dagentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000

4. Application Servers

4.应用服务器

While Spring Boot has become very popular in recent years, traditional application servers are still quite prevalent in modern software architectures. In this section, we’ll look at how to enable debug for some of the more popular applications servers.

虽然 Spring Boot 近年来非常流行,但传统的应用服务器在现代软件架构中仍然相当普遍。在本节中,我们将探讨如何为一些比较流行的应用服务器启用调试功能。

Most application servers provide a script for starting and stopping applications. Enabling debug is typically just a matter of adding additional arguments to this script and/or setting additional environment variables.

大多数应用服务器提供了一个启动和停止应用程序的脚本。启用调试通常只是向这个脚本添加额外的参数和/或设置额外的环境变量。

4.1. Tomcat

4.1.Tomcat

The startup script for Tomcat is named catalina.sh (catalina.bat on Windows). To start a Tomcat server with debug enabled, we can prepend jpda to the arguments:

Tomcat的启动脚本被命名为catalina.sh(Windows下为catalina.bat)。为了启动一个启用了调试功能的Tomcat服务器,我们可以在参数前加上jpda

catalina.sh jpda start

The default debug arguments will use a network socket listening on port 8000 with suspend=n. These can be changed by setting one or more of the following environment variables: JPDA_TRANSPORT, JPDA_ADDRESS, and JPDA_SUSPEND.

默认的调试参数将使用一个监听8000端口的网络套接字,suspend=n。这些可以通过设置以下一个或多个环境变量来改变。JPDA_TRANSPORT, JPDA_ADDRESS, 和JPDA_SUSPEND

We can also get full control of the debug arguments by setting JPDA_OPTS. When this variable is set, it takes precedence over the other JPDA variables. Thus, it must be a complete debug argument for the JVM.

我们还可以通过设置JPDA_OPTS来获得对调试参数的完全控制。当这个变量被设置后,它将优先于其他JPDA变量。因此,它必须是JVM的一个完整的调试参数。

4.2. Wildfly

4.2.野生蝴蝶

The startup script for Wildfly is stand-alone.sh. To start a Wildfly server with debug enabled, we can add –debug.

Wildfly的启动脚本是stand-alone.sh。要启动一个启用了调试功能的Wildfly服务器,我们可以添加-debug

The default debug mode uses a network listener on port 8787 with suspend=n. We can override the port by specifying it after the –debug argument.

默认的调试模式在8787端口使用一个网络监听器,suspend=n。我们可以通过在-debug参数后指定端口来覆盖它。

For more control over the debug argument, we can just add the complete debug arguments to the JAVA_OPTS environment variable.

为了对调试参数进行更多的控制,我们可以直接将完整的调试参数添加到JAVA_OPTS环境变量。

4.3. Weblogic

4.3.Weblogic

The startup script for Weblogic is startWeblogic.sh. To start a Weblogic server with debug enabled, we can set the environment variable debugFlag to true.

Weblogic的启动脚本是startWeblogic.sh。要在启动Weblogic服务器时启用调试功能,我们可以将环境变量debugFlag设为true

The default debug mode uses a network listener on port 8453 with suspend=n. We can override the port by setting the DEBUG_PORT environment variable.

默认的调试模式在8453端口使用一个网络监听器,suspend=n。我们可以通过设置DEBUG_PORT环境变量来覆盖这个端口。

For more control over the debug argument, we can just add the complete debug arguments to the JAVA_OPTIONS environment variable.

为了对调试参数进行更多的控制,我们可以直接将完整的调试参数添加到JAVA_OPTIONS环境变量。

The latest versions of Weblogic also provide a Maven plugin to start and stop servers. This plugin will honor the same environment variables as the startup script.

最新版本的Weblogic还提供了一个Maven插件来启动和停止服务器。该插件将尊重与启动脚本相同的环境变量

4.4. Glassfish

4.4.Glassfish

The startup script for Glassfish is asadmin. To start a Glassfish server with debug enabled, we have to use –debug:

Glassfish的启动脚本是asadmin。要启动一个启用了调试功能的Glassfish服务器,我们必须使用-debug

asadmin start-domain --debug

The default debug mode uses a network listener on port 9009 with suspend=n.

默认的调试模式使用9009端口的网络监听器,suspend=n

4.5. Jetty

4.5.喷气式飞机

The Jetty application server doesn’t come with a startup script. Instead, Jetty servers are started using the java command.

Jetty应用服务器并不带有启动脚本。相反,Jetty服务器是使用java命令启动的。

Thus, enabling debugging is as simple as adding the standard JVM command line arguments.

因此,启用调试就像添加标准JVM命令行参数一样简单。

5. Debugging From an IDE

5.从IDE中调试

Now that we’ve seen how to enable debugging in various application types, let’s look at connecting a debugger.

现在我们已经看到了如何在各种类型的应用程序中启用调试,让我们看看如何连接调试器。

Every modern IDE offers debugging support. This includes both the ability to start a new process with debugging enabled, as well as the ability to debug an already running process.

每个现代IDE都提供调试支持。这既包括启动一个启用了调试功能的新进程的能力,也包括调试一个已经运行的进程的能力。

5.1. IntelliJ

5.1.IntelliJ

IntelliJ offers first-class support for Spring and Spring Boot applications. Debugging is as simple as navigating to the class with the main method, right-clicking the triangle icon, and choosing Debug:

IntelliJ为 Spring 和 Spring Boot 应用程序提供一流的支持。调试很简单,只要导航到具有main方法的类,右键单击三角形图标,然后选择调试。

intellij run gutter - icon

If a project contains multiple Spring Boot applications, IntelliJ will provide a Run Dashboard tool window. This window lets us debug multiple Spring Boot applications from a single place:

如果一个项目包含多个Spring Boot应用程序,IntelliJ将提供一个Run Dashboard工具窗口。这个窗口可以让我们从一个地方调试多个Spring Boot应用程序。

intellij spring run dashboard

For applications using Tomcat or other web servers, we can create a custom configuration for debugging. Under Run > Edit Configurations, there are a number of templates for the most popular application servers:

对于使用Tomcat或其他Web服务器的应用程序,我们可以创建一个自定义的配置来进行调试。在 Run > Edit Configurations 下,有一些最流行的应用服务器的模板。

intellij run debug templates

Finally, IntelliJ makes it very easy to connect to any running process and debug it. As long as the application was started with the proper debug arguments, IntelliJ can connect to it, even if it’s on another host.

最后,IntelliJ使得连接到任何正在运行的进程并对其进行调试变得非常容易。只要应用程序是以适当的调试参数启动的,IntelliJ就可以连接到它,即使它是在另一台主机上。

On the Run/Debug Configurations screen, the Remote template will let us configure how we want to attach to the already running application:

运行/调试配置屏幕上,远程模板将让我们配置我们要如何附加到已经运行的应用程序。

intellij remote debug configuration

Note that IntelliJ only needs to know the hostname and debug port. As a convenience, it tells us the proper JVM command line arguments that should be used on the application that we want to debug.

注意,IntelliJ只需要知道主机名和调试端口。为了方便起见,它告诉我们应该在我们要调试的应用程序上使用适当的JVM命令行参数。

5.2. Eclipse

5.2.Eclipse

The quickest way to debug a Spring Boot application in Eclipse is to right-click the main method from either the Package Explorer or Outline windows:

在Eclipse中调试Spring Boot应用程序的最快方法是在Package ExplorerOutline窗口中右键单击main方法。

eclipse debug java application

The default installation of Eclipse doesn’t support Spring or Spring Boot out of the box. However, there is a Spring Tools add-on available in the Eclipse Marketplace that provides Spring support comparable to IntelliJ.

Eclipse的默认安装不支持Spring或Spring Boot。但是,Eclipse 市场上有一个Spring 工具插件,它提供了与 IntelliJ 相当的 Spring 支持。

Most notably, the add-on provides a Boot Dashboard that lets us manage multiple Spring Boot applications from a single place:

最值得注意的是,该插件提供了一个Boot Dashboard,让我们从一个地方管理多个Spring Boot应用程序

eclipse spring boot dashboard

The add-on also provides a Spring Boot Run/Debug Configuration that allows us to customize the debug of a single Spring Boot application. This customized view is available from all the same places as the standard Java Application configuration.

该插件还提供了一个Spring Boot运行/调试配置,允许我们定制单个Spring Boot应用程序的调试。这个定制的视图可以从所有与标准Java Application配置相同的地方获得。

To debug an already running process, either locally or on a remote host, we can use the Remote Java Application configuration:

要调试一个已经运行的进程,无论是在本地还是在远程主机上,我们可以使用远程Java应用程序配置。

eclipse ide remote debug configuration

6. Debugging With Docker

6.用Docker进行调试

Debugging a Spring application inside a Docker container may require additional configuration. If the container is running locally, and isn’t using host network mode, then the debug port won’t be accessible outside the container.

调试Docker 容器内的Spring 应用程序可能需要额外的配置。如果容器在本地运行,并且没有使用主机网络模式,那么调试端口将无法在容器外访问。

There are several ways to expose the debug port in Docker.

有几种方法可以在Docker中暴露调试端口。

We can use –expose with the docker run command:

我们可以使用-exposedocker run命令。

docker run --expose 8000 mydockerimage

We can also add the EXPOSE directive to the Dockerfile:

我们还可以将EXPOSE指令添加到Dockerfile中。

EXPOSE 8000

Or, if we’re using Docker Compose, we can add it into the YAML:

或者,如果我们使用Docker Compose,我们可以把它添加到YAML中。

expose:
 - "8000"

7. Conclusion

7.结论

In this article, we discussed how to enable debugging for any Java application.

在这篇文章中,我们讨论了如何为任何Java应用程序启用调试。

By simply adding a single command line argument, we can easily debug any Java application.

通过简单地添加一个命令行参数,我们可以轻松地调试任何Java应用程序。

We also learned that both Maven and Gradle, as well as most popular IDEs, all have specialized add-ons to make debugging Spring and Spring Boot applications even easier.

我们还了解到,无论是Maven和Gradle,还是大多数流行的IDE,都有专门的附加组件,使调试Spring和Spring Boot应用更加容易。