1. 簡介
調試是編寫軟件最重要的工具之一。
在本教程中,我們將回顧如何調試 Spring 應用的一些方法。
我們還將演示 Spring Boot、傳統應用程序服務器和 IDE 如何簡化這一過程。
2. Java 調試參數
首先,讓我們看看 Java 默認提供什麼。
默認情況下,JVM 不啓用調試功能。 這是因為調試會增加 JVM 內部的額外開銷。 此外,對於公開可訪問的應用程序,調試也可能存在安全問題。
因此,調試應僅在開發期間進行,絕不應用於生產系統。
在我們可以附加調試器之前,我們必須首先配置 JVM 以允許調試。 我們將通過為 JVM 設置命令行參數來完成此操作:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000讓我們來分解一下這些值的含義:
-agentlib:jdwp
這啓用 JVM 內部的 Java Debug Wire Protocol (JDWP) 代理。 這是主要命令行參數,用於啓用調試。
transport=dt_socket
這使用網絡套接字進行調試連接。 其他選項包括 Unix 套接字和共享內存。
server=y
這偵聽傳入的調試器連接。 當設置為 n 時,進程將嘗試連接到調試器,而不是等待傳入連接。 當設置為 n 時,需要提供額外的參數。
suspend=n
這意味着在啓動時不要等待調試連接。 應用程序將正常啓動和運行,直到附加調試器。 當設置為 y 時,進程將在附加調試器之前不會啓動。
address=8000
這是 JVM 監聽傳入調試連接的網絡端口。
上述值是標準且適用於大多數用例和操作系統。 JPDA 連接指南 提供了更詳細的信息。
2.1. JDK9+ 綁定地址
在 JDK8 及以下版本中,將 address 屬性設置為端口號(如示例中所示 address=8000)意味着 JVM 會監聽所有可用的 IP 地址。因此,遠程連接是默認可用的。
此行為在 JDK9+ 版本中已發生改變,主要是出於安全考慮。目前,默認設置僅允許 localhost 連接。
這意味着,為了使遠程連接可用,我們需要在端口號前加上主機名,例如 address=myhost:8000,或者使用 asterisk 來監聽所有可用的 IP 地址,例如 address=*:8000。
3. Spring Boot 應用
有幾種方法 可以啓動 Spring Boot 應用。 最簡單的方法是從命令行使用 java 命令,並帶有 -jar 選項。
要啓用調試,我們只需使用 -D 選項添加 debug 參數:
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000 -jar myapp.jar使用 Maven,我們可以使用提供的 run 目標來啓動我們的應用程序,並啓用調試功能:
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000"同樣,使用 Gradle 時,我們也可以使用 bootRun 任務。首先,我們需要更新 build.gradle 文件,以確保 Gradle 將命令行參數傳遞給 JVM:
bootRun {
systemProperties = System.properties
}現在我們可以執行 bootRun 任務:
gradle bootRun -Dagentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=80004. 應用服務器
儘管近年來 Spring Boot 越來越受歡迎,但在現代軟件架構中,傳統的應用服務器仍然非常普遍。 在本節中,我們將探討如何為一些流行的應用服務器啓用調試。
大多數應用服務器都提供一個啓動和停止應用程序的腳本。 啓用調試通常只需在腳本中添加額外的參數,或者設置額外的環境變量。
4.1. Tomcat
Tomcat 的啓動腳本名為 <em >catalina.sh</em > (catalina.bat 在 Windows 上)。要以調試模式啓動 Tomcat 服務器,可以將 <em >jpda</em > 添加到參數的前面:
catalina.sh jpda start默認調試參數將使用一個監聽在 8000 端口的網絡套接字,且 suspend=n。可以通過設置以下一個或多個環境變量來更改這些參數:JPDA_TRANSPORT, JPDA_ADDRESS, 和 JPDA_SUSPEND.
我們還可以通過設置 JPDA_OPTS 完全控制調試參數。當此變量被設置時,它將優先於其他 JPDA 變量,因此它必須是 JVM 的完整調試參數。
4.2. Wildfly
The startup script for Wildfly is <em >stand-alone.sh</em>. To start a Wildfly server with debug enabled, we can add <em >–debug</em>.
The default debug mode uses a network listener on port 8787 with <em >suspend=n</em>. We can override the port by specifying it after the <em >–debug</em> argument.
For more control over the debug argument, we can just add the complete debug arguments to the <em >JAVA_OPTS</em> environment variable.
4.3. Weblogic
啓動 Weblogic 腳本為 startWeblogic.sh。要啓動帶有調試啓用的 Weblogic 服務器,可以將環境變量 debugFlag 設置為 true。
默認調試模式使用端口 8453 的網絡監聽器,且 suspend=n。可以通過設置環境變量 DEBUG_PORT 來覆蓋端口。
要對調試參數進行更精細的控制,可以將完整的調試參數添加到 JAVA_OPTIONS 環境變量中。
最新版本的 Weblogic 還提供 Maven 插件來啓動和停止服務器。該插件將尊重啓動腳本中使用的相同環境變量。
<h3><strong>4.4. Glassfish</strong></h3><p>啓動 Glassfish 腳本是 <em >asadmin</em>。要以調試模式啓動 Glassfish 服務器,我們需要使用 <em >–debug</em>:</p>
asadmin start-domain --debug默認調試模式使用一個在端口 9009 上運行的網絡監聽器,並使用 suspend=n。
4.5. Jetty
Jetty 應用服務器不自帶啓動腳本。相反,Jetty 服務器使用 java 命令啓動。
因此,啓用調試非常簡單,只需添加標準的 JVM 命令行參數即可。
5. 從 IDE 進行調試
現在我們已經瞭解瞭如何在各種應用程序類型中啓用調試,接下來讓我們看看如何連接調試器。
每個現代 IDE 均提供調試支持。這包括啓動具有調試功能的全新進程的能力,以及調試已運行進程的能力。
<h3><strong>5.1. IntelliJ</strong></h3><p><strong>IntelliJ</strong><strong> 對 Spring 和 Spring Boot 應用程序提供一流的支持。</strong>調試就像導航到帶有 <em>main</em> 方法的類,右鍵單擊三角形圖標,然後選擇“調試”:</p><img src="/file/story/attachments/image/l/c4c68984-dcd1-4de8-b61b-bcbbc6a209a1"><p><strong>對於 Spring Boot 應用程序,IntelliJ IDEA 提供了一個專用插件——Spring Debugger。</strong>該插件允許我們查看已加載的 Bean、實際屬性值和數據庫連接等,均在 IDE 中可見。它適用於從 2025.2 版本及更高版本的高端版 IDEA。</p><p>如果一個項目包含多個 Spring Boot 應用程序,IntelliJ 將提供 Run Dashboard 工具窗口。該窗口允許我們從一個地方調試多個 Spring Boot 應用程序:</p><img src="/file/story/attachments/image/l/4f0b9c75-76c4-459d-a89c-3fca2d307c3d"><p>對於使用 Tomcat 或其他 Web 服務器的應用程序,我們可以為調試創建自定義配置。在 <em>Run</em> > <em>Edit Configurations</em> 下,有許多用於最受歡迎的應用程序服務器的模板:</p><img src="/file/story/attachments/image/l/18b86885-65e0-439f-a9a3-6d282f96cdf9"><p>最後,IntelliJ 使得連接到任何正在運行的進程並進行調試變得非常容易。 <strong as long as the application was started with the proper debug arguments</strong>,IntelliJ 可以在另一台主機上連接到它,即使它已啓動:</p><p>在 <em>Run/Debug Configurations</em> 屏幕上,<em>Remote</em> 模板將允許我們配置如何附加到已運行的應用程序:</p><img src="/file/story/attachments/image/l/7d140ce9-fe3e-41f9-b941-bbe3fc1151eb"><p>請注意,IntelliJ 只需要知道主機名和調試端口。為了方便起見,它會告訴我們應該在要調試的應用程序上使用的正確 JVM 命令行參數。</p>
5.2. Eclipse
使用 Eclipse 調試 Spring Boot 應用程序最快的方法是右鍵單擊主方法,從 Package Explorer 或 Outline 窗口中:
Eclipse 的默認安裝不支持 Spring 或 Spring Boot。但是,Eclipse Marketplace 中有一個 Spring Tools 插件,它提供了與 IntelliJ 類似的可比的 Spring 支持。
最重要的是,該插件提供了一個 Boot 面板,允許我們在單個位置管理多個 Spring Boot 應用程序:
該插件還提供了一個 Spring Boot 運行/調試配置,允許我們自定義單個 Spring Boot 應用程序的調試。 此自定義視圖可在與標準 Java Application 配置相同的地點訪問。
要調試正在運行的進程(無論本地還是遠程主機),我們可以使用 Remote Java Application 配置:
6. 使用 Docker 進行調試
在 Docker 容器內部調試 Spring 應用程序可能需要額外的配置。 如果容器在本地運行,且未使用宿主機網絡模式,則調試端口將無法從外部訪問。
在 Docker 中暴露調試端口有多種方法。
我們可以使用 –expose 選項與 docker run 命令結合使用:
docker run --expose 8000 mydockerimage我們還可以將 EXPOSE 指令添加到 Dockerfile 中:
EXPOSE 8000或者,如果使用 Docker Compose,我們可以將其添加到 YAML 中:
expose:
- "8000"7. 結論
在本文中,我們討論瞭如何為任何 Java 應用程序啓用調試功能。
只需添加一個命令行參數,我們就可以輕鬆地調試任何 Java 應用程序。
我們還了解到,Maven、Gradle 以及大多數流行的 IDE 都具有專門的附加組件,可以更輕鬆地調試 Spring 和 Spring Boot 應用程序。