StackTraces
Spring Boot已驗證

Spring Boot 啟動報 Port 8080 was already in use

@debug_master32 天前更新閱讀 6 min00

一句話先說結論:Spring Boot 內嵌的 Web 服務器預設監聽 8080,一旦已有進程佔著這個端口,JVM 拋 BindException,應用直接啟動失敗。解決無非兩條:找到並結束佔用進程,或者換個端口。這是最基礎的坑,但每次都有人栽在“IDE 沒停乾淨”上。

背景

Spring Boot 用內嵌容器(預設 Tomcat)讓應用“打成 jar 直接跑”,不需要額外部署到獨立 Tomcat。帶來的一個副作用是:內嵌容器預設綁定 8080 端口。這個端口同時也是 Tomcat 獨立版、Jenkins、Nexus、以及各種開發工具預設愛用的端口,衝突概率極高。

現象

啟動時立即失敗,控制台報:

***************************
APPLICATION FAILED TO START
***************************

Description:

Web server failed to start. Port 8080 was already in use.

Action:

Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.

底層例外是 Tomcat 的 BindException:

org.apache.catalina.LifecycleException: Protocol handler start failed
	at org.apache.catalina.core.StandardServer.start(StandardServer.java:558)
	at org.apache.catalina.startup.Catalina.start(Catalina.java:387)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:345)
	at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:431)
Caused by: java.net.BindException: Address already in use: bind
	at java.net.PlainSocketImpl.socketBind(Native Method)
	at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:388)
	at java.net.ServerSocket.bind(ServerSocket.java:372)
	at java.net.ServerSocket.<init>(ServerSocket.java:234)
	at org.apache.tomcat.util.net.ServerSocketFactoryImpl.createServerSocket(ServerSocketFactoryImpl.java:83)
	at org.apache.tomcat.util.net.ServerSocketFactoryImpl.createServerSocket(ServerSocketFactoryImpl.java:64)
	at org.apache.coyote.AbstractProtocol$ProtocolBinding.init(AbstractProtocol.java:535)
	... 12 more

同一時刻一個端口只能有一個進程監聽,第二個人再來綁就會失敗。

根因分析

消息本身已經說得很明白:8080 被佔了。值得記的是它為什麼被佔——常見四種:

  1. 上一個實例沒停乾淨:在 IDE 裡又重新點了一次 Run,前一個 java 進程還活著,或者 java -jar 在後臺跑著。
  2. IDE 留下了殭屍進程:IntelliJ/Eclipse 在崩潰或強停後,有時不會真正結束 Java 進程。
  3. 別的服務預設也用 8080:獨立 Tomcat、Jenkins、Nexus、WildFly 等。
  4. Docker 容器映射了 8080:容器裡跑的可能完全是別的服務,但宿主機這一側的端口綁定照樣擋住你的 Spring Boot 應用。

解決方案

方案 A:找到並結束佔用進程

一條命令先查出是誰佔了端口。

macOS / Linux:

lsof -i :8080

輸出裡 PID 那列就是進程號,例如:

COMMAND   PID  USER   FD  TYPE DEVICE SIZE/OFF NODE NAME
java    18902  marco  48u IPv6 ...  0t0  TCP *:8080 (LISTEN)

先嚐試優雅退出,不行再強殺(-9 是最後手段,不留給進程做清理的機會):

kill 18902
# 若还活着
kill -9 18902

一條命令直接查 PID 並殺掉:

kill -9 $(lsof -ti :8080)

Windows:

netstat -ano | findstr :8080
:: 最后那列就是 PID
taskkill /PID 1234 /F

如果是 Docker 佔的端口,先定位容器:

docker ps --filter publish=8080

方案 B:換個端口

不想動別人的進程,就讓自己的應用換端口。

application.properties:

server.port=8081

application.yml:

server:
  port: 8081

命令行臨時指定:

java -jar your-app.jar --server.port=8081

環境變數(藉助 Spring Boot 的 relaxed binding,SERVER_PORT 會自動映射到 server.port):

export SERVER_PORT=8081
java -jar your-app.jar

方案 C:測試時用隨機端口

集成測試或本地起多個實例時,把端口設成 0,讓容器選一個空閒端口:

server.port=0

運行時通過 @Value("${local.server.port}") 拿到實際端口。

小結

  • 端口占用是“資源衝突”,不是程式碼問題,先查 lsof/netstat 再決定殺還是換。
  • kill -9 是最後手段,能優雅退出就別強殺。
  • 記住設定優先級:命令行參數 > 環境變數 > 設定文件 > 預設 8080,端口改了沒生效多半是更高優先級的來源覆蓋了它。
  • 預防:IDE 裡用 Stop 停乾淨再 Run;不同服務約定不同端口;順手 docker ps 看看有沒有容器佔著。

References(參考來源)

最後更新於 2026-09-09

這篇幫到你了嗎?

剛解決了一個棘手的報錯?花兩分鐘記錄下來,幫助下一個遇到同樣問題的開發者。

貢獻一條解法