StackTraces
Spring Boot已驗證

Spring Boot 報 NoSuchBeanDefinitionException

@debug_master32 天前更新閱讀 6 min00

報 NoSuchBeanDefinitionException: No qualifying bean of type ... available 十有八九不是程式碼寫錯,是 Spring 壓根沒掃到這個類。Spring Boot 預設只掃描主類所在包和它的子包,Bean 定義在別的包、或少了 @Service 這類註解,容器裡就沒有它。

Issue & Env(案發現場與環境)

  • 業務場景:分模塊或多包工程裡,UserService 定義在一個包,UserController 在另一個包,注入時啟動失敗;或 Bean 類漏寫 @Service / @Component。
  • 環境:Spring Boot 2.x / 3.x 通用。預設元件掃描行為由 @SpringBootApplication 裡的 @ComponentScan 決定。

StackTrace(堆疊日誌)

典型的注入失敗堆疊,UnsatisfiedDependencyException 包著 NoSuchBeanDefinitionException:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userController' defined in file [/Users/dev/demo/target/classes/com/example/demo/UserController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.service.UserService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
	at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911)
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:788)
	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1388)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1341)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:612)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:339)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:962)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:930)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:596)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:732)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:405)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:305)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1307)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1296)
	at com.example.demo.Application.main(Application.java:12)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.service.UserService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
	at org.springframework.beans.factory.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:2126)
	at org.springframework.beans.factory.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:2093)
	at org.springframework.beans.factory.DefaultListableBeanFactory.doResolveBeanForType(DefaultListableBeanFactory.java:1747)
	at org.springframework.beans.factory.DefaultListableBeanFactory.doResolveMultipleBeans(DefaultListableBeanFactory.java:1383)
	at org.springframework.beans.factory.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1313)
	at org.springframework.beans.factory.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1575)
	at org.springframework.beans.factory.DefaultListableBeanFactory.doResolveMultipleBeans(DefaultListableBeanFactory.java:1351)
	at org.springframework.beans.factory.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1313)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AutowireCapableBeanFactory.java:738)
	... 19 more

Reproduce(復現程式碼)

主類放在 com.example.demo,Service 卻放在平級之外的 com.example.service:

// com/example/demo/Application.java
package com.example.demo;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
// com/example/service/UserService.java —— 在 com.example.demo 之外
package com.example.service;

@Service
public class UserService {
    public void hello() {}
}
// com/example/demo/UserController.java
package com.example.demo;

@RestController
public class UserController {
    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }
}

啟動即拋上面那段 NoSuchBeanDefinitionException。UserService 有 @Service 註解,但它在預設掃描路徑之外,容器沒把它登記為 Bean。

Root Cause(根因分析)

@SpringBootApplication 是一個組合註解,其中包含 @ComponentScan。@ComponentScan 沒有顯式指定 basePackages 時,掃描起點是聲明這個註解的類所在的包——也就是主類 Application 所在的 com.example.demo,以及它的所有子包。

com.example.service 和 com.example.demo 是平級兄弟包,既不是子包也不包含主類包,自然不在掃描範圍內。於是 UserService 有註解也不會被 ClassPathScanningCandidateComponentProvider 找到,容器裡沒有「類型為 UserService 的 Bean」,注入時報 NoSuchBeanDefinitionException。

另一個高頻變體是註解漏寫:類沒有 @Service / @Component / @Repository,即使在同一包內也不會被掃描登記。

還有一個更容易翻車的寫法——把 @ComponentScan 的範圍寫錯。spring-boot issue #16063 裡,有人在主類上寫 @ComponentScan("*.*"),掃描範圍直接擴到整個依賴 jar,連 spring-boot-autoconfigure 裡的自動設定類都被掃進去,報的是 BeanDefinitionStoreException。根子是同一個:@ComponentScan 的邊界沒搞清。

The Fix(解決方案)

首選:把 Bean 挪到主類包下面

最省事也最乾淨,讓目錄跟隨主類包:

com.example.demo
├── Application.java
├── controller
│   └── UserController.java
└── service
    └── UserService.java

service 變成 com.example.demo 的子包,預設掃描能覆蓋,無需任何額外設定。

跨包場景:顯式聲明掃描範圍

Bean 在 Maven/Gradle 多模塊或第三方包裡,就主動擴大掃描範圍:

@SpringBootApplication(scanBasePackages = {
    "com.example.demo",
    "com.example.service"
})
public class Application {}

或單獨標註:

@SpringBootApplication
@ComponentScan(basePackages = {"com.example.demo", "com.example.service"})
public class Application {}

註解漏寫:補上 stereotype

確認類裡有對應註解:

@Service
public class UserService { ... }

Mapper 接口這類非 @Component 的 Bean,配合 @MapperScan("com.example.demo.mapper") 顯式指定掃描包,別指望預設元件掃描。

References(參考來源)

最後更新於 2026-09-09

這篇幫到你了嗎?

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

貢獻一條解法