
1. 問題現(xiàn)象與影響范圍先描述一下這個報錯的樣子。如果你在 IDEA 里啟動一個 Spring Boot 項目控制臺刷出類似這樣的堆棧*************************** APPLICATION FAILED TO START *************************** Description: Web application could not be started as there was no ServletWebServerFactory defined in the application context. Action: Consider adding an explicit Bean definition of ServletWebServerFactory, or adding spring-boot-starter-web to your classpath.還沒等你看到 Spring Boot 的 Logo 和端口號應用就退出。這種情況在 Spring Boot 2.x 項目中非常典型但不少人在第一次遇到時會被ServletWebServerFactory這個類名嚇住以為是自己寫的某個配置寫錯了或者 IDEA 的 Run Configuration 配錯了。實際上這個錯誤的核心含義是Spring Boot 沒有在應用上下文里找到一個可用于創(chuàng)建內嵌 Web 服務器的工廠 Bean。換句話說Spring Boot 根本不知道你要跑的是一個 Web 應用。而 Spring Boot 判斷你要不要啟動 Web 服務器的邏輯完全取決于它從 classpath 里掃描到了什么依賴。這個報錯波及的人群很廣剛上手 Spring Boot 的新手、從 Spring Boot 1.x 升級到 2.x/3.x 的老手、用 IDEA 打開別人項目后直接點 Run 的同學都會遇到。有些人能很快解決有些人卻折騰一兩個小時問題往往出在一個很小但極易被忽略的細節(jié)上。2. 根本原理Spring Boot 是怎么決定“我要不要啟動 Web 服務器”的要解決這個報錯不能只停留在加依賴的層面得先把 Spring Boot 對 Web 應用類型的判斷機制講清楚。Spring Boot 在啟動時會執(zhí)行一個核心步驟——推斷當前應用的WebApplicationType。這個類型一共有三種類型推斷依據典型場景NONEclasspath 中沒有任何 Web 相關依賴純后臺任務、定時任務SERVLETclasspath 中存在javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext傳統(tǒng) Servlet Web 應用絕大多數 Spring Boot Web 項目REACTIVEclasspath 中存在org.springframework.web.reactive.DispatcherHandler且不存在Servlet相關類WebFlux 響應式項目如果推斷結果為 NONESpring Boot 會以非 Web 應用方式啟動不會創(chuàng)建內嵌 Tomcat/Jetty/Undertow。這時候如果你在代碼里寫了RestController、Controller這類 Web 層注解或者調用了需要 Servlet 容器的組件應用能啟動成功但永遠不會監(jiān)聽端口。而missing ServletWebServerFactory這個報錯實際上是 Spring Boot 在項目里已經存在 Web 相關代碼比如你有 controller、有SpringBootApplication主類但它在上下文里找不到ServletWebServerFactory的實現(xiàn)類時主動拒絕繼續(xù)啟動。它給出的 Action 提示也很有指導性加spring-boot-starter-web到 classpath或者顯式聲明一個ServletWebServerFactory的Bean關鍵邏輯就藏在這里Spring Boot 自動配置里的ServletWebServerFactoryAutoConfiguration是條件裝配的。它的生效條件是ConditionalOnClass(ServletRequest.class) ConditionalOnWebApplication(type Type.SERVLET)也就是說只有當 classpath 里有 Servlet API且應用被判定為 Servlet Web 應用時Spring Boot 才會自動配置 Tomcat 等內嵌容器相關的工廠 Bean。缺少任何一環(huán)這個自動配置類都不會生效。從 Spring Boot 2.3 開始官方還用spring-boot-web-server-*的方式簡化了內嵌 Web 服務器的切換比如只引入spring-boot-starter-tomcat但最常用的還是完整引入spring-boot-starter-web它會幫你帶上Spring MVC內嵌 TomcatJackson JSON 處理Spring Boot 對 Web 場景的全部自動配置所以當你看到這個報錯時腦子里要有一個檢查順序classpath 里有沒有 servlet-api → 有沒有 spring-webmvc → 有沒有內嵌容器實現(xiàn) → Spring Boot 自動配置有沒有被加載。絕大多數情況下崩潰點都出在第一環(huán)或最后一環(huán)。3. 逐個排查哪些原因會造成這個報錯3.1 最常見的原因pom.xml 漏掉了 spring-boot-starter-web這個原因占所有報錯場景的七成以上。尤其是當你用 IDEA 的 Spring Initializr 創(chuàng)建項目時沒有勾選 Spring Web或者從網上找了一個代碼片段只復制了 controller 層代碼卻沒有復制完整的 pom.xml。打開你的 pom.xml注意檢查這一塊parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version relativePath/ /parent如果 parent 在再看 dependencies 里是否有dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency兩樣都齊了再確認 parent 里聲明的spring-boot-starter-parent的版本號是真實存在的。版本號寫一個不存在的值依賴解析會失敗classpath 會缺一堆東西報的錯也五花八門。還有一個小概率場景有人喜歡用spring-boot-starter-webflux來做 Web 開發(fā)。WebFlux 是響應式棧而非 Servlet 棧。如果你同時引入了 webflux 和 web 兩個 starterSpring Boot 會優(yōu)先判定為 REACTIVE 類型此時 Tomcat 不會被配置同樣可能出現(xiàn) ServletWebServerFactory 相關的異常。解決方案是只保留一個 Web starter絕大多數業(yè)務項目選spring-boot-starter-web即可。3.2 常見原因之二Spring Boot 版本與依賴不兼容這個坑我踩過好幾次屬于那種配置看著全對但就是起不來的情況。Spring Boot 2.x 和 3.x 是兩條完全不同的技術基線。Spring Boot 2.x 基于javax.servletAPISpring Boot 3.x 基于jakarta.servletAPI。如果你把spring-boot-starter-web的版本鎖在了 2.x而項目其他組件引入了 Jakarta 命名空間下的 Servlet 相關類或者反過來自動配置的匹配條件就會失效。再細說一個更隱蔽的你不小心多加了一個javax.servlet-api的依賴但版本是 4.0.1而 Spring Boot 2.7 內部自帶的是 Tomcat 9.0.x對應 Servlet 4.0。這本身沒問題。但如果你手動加的是javax.servlet-api3.x內嵌 Tomcat 8 的某些初始化路徑就會異常更糟糕的是可能導致ServletWebServerFactoryAutoConfiguration的ConditionalOnClass判斷通過但真正的容器工廠創(chuàng)建失敗。所以我的建議是除非你明確知道自己需要自定義 Servlet 容器版本否則不要在 Spring Boot 項目中手動引入任何 Servlet API 依賴把版本選擇權完全交給 Spring Boot 的 BOMBill of Materials。BOM 已經替你統(tǒng)一管理了 Tomcat、Jetty、Undertow 的版本你手動加舊版本反而會打破這個平衡。3.3 常見原因之三自動配置被禁用Spring Boot 允許你在application.properties/application.yml里用一個開關關掉某些自動配置spring.autoconfigure.excludeorg.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration這個寫法的場景是你確實不需要內嵌 Web 服務器想用外部 Tomcat 部署 war 包或者你想完全自己手動定義容器。但如果你不小心從網上復制了一段配置沒注意或者因為排錯時試過這個項而忘了刪Spring Boot 就不會去創(chuàng)建 ServletWebServerFactory。這種情況的判斷方法是去項目里搜一下spring.autoconfigure.exclude一眼就能看出來。有就刪掉基本解決。同理還有一個原因是SpringBootApplication的exclude屬性里手動排除了這個自動配置類SpringBootApplication(exclude { ServletWebServerFactoryAutoConfiguration.class })這種寫法同樣會導致報錯但出現(xiàn)概率比 properties 里的更低因為它需要你精確寫出類名誤配的可能性不大。3.4 不常見但很坑IDEA 緩存和 Maven 依賴狀態(tài)異常有一類場景是代碼和配置都對但項目就是起不來。這時候十有八九是 IDE 緩存或 Maven 本地倉庫出了問題。IDEA 對 Maven 依賴的解析有自己的緩存機制。如果你改動了 pom.xmlIDEA 沒有重新導入或者導入過程半途失敗classpath 就會處于一個看起來改了實際上沒生效的中間態(tài)。常見的表現(xiàn)就是你明明加了spring-boot-starter-web重新點運行報錯依舊。這種場景的排查步驟通常是先看 IDEA 右側 Maven 面板展開Dependencies找一下有沒有spring-boot-starter-web。如果沒找到說明依賴導入沒有完成。點 Maven 面板上方的刷新按鈕Reload All Maven Projects。如果刷新后還是不行執(zhí)行 Maven 的clean再接執(zhí)行package看看命令行里是不是有依賴解析失敗的報錯。如果 IDE 無論如何都不正常直接放棄 IDEA 里的舊狀態(tài)用終端命令驗證mvn clean compile如果命令行里編譯通過說明 Maven 本身沒問題問題就在 IDE 的緩存索引。這時候可以嘗試mvn -U clean install強制更新快照依賴并重新生成本地倉庫緩存。再不行就重啟 IDEA讓它重新建立索引。Maven 本地倉庫本身也可能存在損壞狀態(tài)。.m2/repository里的_remote.repositories、.lastUpdated文件如果殘留了一些失敗狀態(tài)會導致依賴解析時拿不到正確版本。最簡單的暴力方案是刪掉.m2/repository/org/springframework/boot整個目錄重新讓 Maven 下載。代價是又要等好幾分鐘的下載但至少排除一個變量。3.5 IDEA 社區(qū)版特有的一個問題熱搜詞里出現(xiàn)大量intellij idea 社區(qū)版相關的搜索這也說明很多人在用社區(qū)版跑 Spring Boot。IDEA 社區(qū)版必須明確一點它本身不內置對于 Spring Boot 項目的完整框架支持但它可以像普通 Java 項目一樣編譯運行 Spring Boot 應用。問題出在社區(qū)版對 Maven 項目的導入有時不會自動觸發(fā) Spring 插件相關的 facet 配置導致項目結構看起來有點卡。不過這不影響應用啟動。真正容易在社區(qū)版上踩的坑是你用社區(qū)版直接打開了一個從 Gitee 上拉取的多模塊 Maven 項目父模塊依賴子模塊但子模塊沒有正確安裝到本地倉庫Spring Boot 主模塊在啟動時找不到兄弟模塊的類報錯五花八門解決方式是先把所有模塊 install 到本地倉庫mvn clean install -DskipTests然后在主模塊的 pom 里確認依賴的是項目版本號而不是 SNAPSHOT 缺省值。這個操作在專業(yè)版和社區(qū)版中并無差別主要是很多新人不知道要這么做。4. 實操解決步驟從報錯到跑通的完整流程把排查思路串成一套可復制的步驟。這套流程我自己在帶新人時反復用過基本能在十分鐘內定位問題。4.1 第一步確認項目類型和啟動方式先看項目是被當成什么方式啟動的。在 IDEA 里點開右上角的 Run Configuration看看你是用Spring Boot模式啟動還是用Application普通 Java 模式啟動。Spring Boot 3 項目必須有主類而且主類上要有SpringBootApplication注解。確認你運行的類就是這個主類而不是某個Configuration類也不是某個測試類。package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }如果你在這個主類里加了spring.main.web-application-typenone配置或者在 application.yml 里寫了spring.main.web-application-type: none那你等于強制告訴 Spring Boot 這不是 Web 應用。這種情況下的missing ServletWebServerFactory是無意義的——你手動掐斷了 Web 啟動路徑。檢查一下有沒有這個配置。4.2 第二步classpath 完整性檢查這是最快的排查動作。打開 pom.xml確認依賴里包含dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency如果你用的是 Gradle對應的是 build.gradleimplementation org.springframework.boot:spring-boot-starter-web確認無誤后在 IDEA 右側 Maven 面板里展開Dependencies搜索tomcat-embed-core、spring-webmvc、spring-boot-starter-tomcat這三個關鍵 artifact。如果任何一個不在列表里說明依賴并沒有真正引入。這時候先執(zhí)行mvn clean install再點 IDEA 的刷新按鈕。4.3 第三步用“排除法”定位自動配置是否生效如果你確定依賴沒問題但還是報錯可以考慮在啟動類上臨時加一個調試輸出確認 WebApplicationType 的推斷結果SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication app new SpringApplication(DemoApplication.class); // 打印推斷出的 Web 應用類型 System.out.println(Web type: app.getWebApplicationType()); app.run(args); } }這里以 Spring Boot 2.x 為例。getWebApplicationType方法會返回NONE、SERVLET或REACTIVE三種枚舉值。如果輸出的是NONE說明 classpath 里根本沒有 Servlet 相關的類回到第二步如果輸出是SERVLET但依然報錯那問題大概率出在自動配置被禁用或容器工廠創(chuàng)建失敗回到第三步繼續(xù)查。4.4 第四步查自動配置排除項搜索整個項目包括 application.properties、application.yml、啟動類注解確認沒有以下任何一項spring.autoconfigure.excludeorg.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfigurationSpringBootApplication(exclude { ServletWebServerFactoryAutoConfiguration.class })如果搜到了直接刪掉。除非你真的知道自己在做什么否則這個配置不該出現(xiàn)在普通 Web 項目里。4.5 第五步清理 IDEA 緩存和 Maven 倉庫到了這一步還沒解決就要動用殺招了先關閉 IDEA。刪除項目里的.idea目錄注意先備份最好不要直接在命令行里強勢刪除用 IDEA 的失效緩存功能更穩(wěn)妥。重啟 IDEA重新打開項目讓它重新導入 Maven。如果依賴還是異常進入 IDEA 設置Settings → Build, Execution, Deployment → Build Tools → Maven → Local repository把路徑記下來然后打開該目錄找到org/springframework/boot目錄將其改名為org/springframework/boot_backup強制重新下載。重新執(zhí)行mvn clean install -DskipTests。這套操作下來90% 的莫名奇妙問題都會消失。剩下的 10% 里大多是系統(tǒng) JDK 版本不匹配這個可以通過java -version和 pom.xml 里的java.version做對比排查。5. 常見問題與排查技巧實錄以下這些問題都是我在實際交流中見過的真實案例整理成速查表方便你直接對照。問題現(xiàn)象可能原因快速驗證辦法剛創(chuàng)建項目就報 missing ServletWebServerFactory創(chuàng)建項目時沒勾選 Spring Web檢查 pom.xml 是否有 spring-boot-starter-web明明加了 starter 還報錯IDEA 沒有重新加載 Maven 依賴點 Maven 面板刷新按鈕跑 mvn clean compile項目能啟動但不監(jiān)聽端口spring.main.web-application-typenone檢查 application.yml 里的配置加了自己下的 servlet-api 后報錯Servlet API 版本和容器不匹配刪掉手動引入的 servlet-api 依賴交給 BOM 管理從 Gitee 拉的項目報錯指向自己的模塊類多模塊未先 install在父模塊執(zhí)行 mvn clean install主類能編譯但啟動報錯JDK 版本和 Spring Boot 不匹配確認 Spring Boot 3.x 需要 JDK 17上次能跑這次突然報錯IDEA 緩存狀態(tài)損壞重啟 IDEA刪除 .idea 目錄重新導入這里特別提醒一個容易被忽略的檢查項IDEA 里的 Language Level 設置。如果你的 IDEA 里項目編譯器默認設置成了 Java 8而 Spring Boot 3.x 必須要 Java 17IDE 的編譯階段可能不會報錯但 Spring Boot 啟動時的字節(jié)碼版本校驗就會失敗報錯信息經常莫名其妙不一定是 missing ServletWebServerFactory但也可能是這一條異常鏈上的間接后果。所以打開Settings → Build, Execution, Deployment → Compiler → Java Compiler把版本調成和你 pom 里java.version一致的版本。6. 還需要注意的同類報錯變體在實際開發(fā)中missing ServletWebServerFactory有時不是孤立出現(xiàn)的。它可能是另外兩個報錯的前奏或者變體。第一個變體是No qualifying bean of type ServletWebServerFactory available出現(xiàn)這個報錯說明ServletWebServerFactoryAutoConfiguration已經生效但容器工廠沒有被成功創(chuàng)建。常見原因是你自定義了一個WebServerFactoryCustomizer但引用了不存在的類或者在配置類里寫了某些 Tomcat 相關的初始化代碼導致 Bean 創(chuàng)建失敗。建議先移除所有自定義的WebServerFactoryCustomizer、TomcatConnectorCustomizer等配置再逐步加回來定位是哪個自定義邏輯破壞了容器創(chuàng)建。第二個變體是Port already in use: 8080這個雖然不是 missing ServletWebServerFactory但和它屬于同一類容器啟動異常。如果你的 8080 端口被占用Spring Boot 會宣布啟動失敗報錯信息里也會有 ServletWebServerFactory 的身影。排查方式是用命令看看誰占用了端口netstat -ano | findstr 8080 taskkill /F /PID PID以上就是我個人在反復踩坑后總結出的全流程排查思路。遇到這個報錯不用慌先想清楚 Spring Boot 推斷 Web 應用類型的機制再按依賴、自動配置、IDE 狀態(tài)三個方向去定位。尤其是當你對自己的配置很有信心時多想想是不是 IDE 緩存這個隱藏殺手在搗亂——我至少有兩次花了半小時看代碼最后靠重啟 IDEA 解決。