How to fix: Spring Boot 3 fails to find bean despite @Service annotation and correct package structure
🚨 Understanding the Error
Section titled “🚨 Understanding the Error”When Spring Boot 3 throws a NoSuchBeanDefinitionException or an UnsatisfiedDependencyException, it indicates that the ApplicationContext—Spring’s internal registry of managed objects—cannot locate a candidate bean for a requested type.
Even when you have annotated a class with @Service and placed it within the package hierarchy, the Component Scan mechanism may fail due to sophisticated filtering, bytecode generation issues in AOT (Ahead-of-Time) processing, or subtle metadata mismatches in the Spring Boot 3 / Jakarta EE 10 baseline.
🔍 Root Cause
Section titled “🔍 Root Cause”| Cause | Technical Detail |
|---|---|
| Package Depth | The class is in a sibling package rather than a sub-package of the @SpringBootApplication class. |
| Proxying Issues | @Service is applied to a class that requires CGLIB/ByteBuddy proxying but lacks a default constructor or is final. |
| Profile Mismatch | The bean is marked with @Profile and the active profile does not match at runtime. |
| AOT Processing | In Spring Boot 3, GraalVM native image AOT processing may have pruned the bean if it’s not reachable via static analysis. |
| Jakarta Migration | Using javax.annotation instead of jakarta.annotation (SB3 uses Jakarta EE 10). |
| Manual Instantiation | Attempting to inject a bean into a class created via the new keyword instead of Spring’s factory. |
🛠️ Step-by-Step Solutions
Section titled “🛠️ Step-by-Step Solutions”1. Verify Application Entry Point Placement
Section titled “1. Verify Application Entry Point Placement”Spring Boot 3 performs a recursive scan starting from the package containing the @SpringBootApplication class. Ensure your service is in a child package.
Incorrect Structure:
com.project.app.Application.javacom.project.service.MyService.java (Sibling - NOT scanned by default)Correct Structure:
com.project.app.Application.javacom.project.app.service.MyService.java (Child - Scanned automatically)If you must use a sibling package, explicitly define the scan base:
@SpringBootApplication(scanBasePackages = "com.project")public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}2. Check for Jakarta EE 10 Namespace
Section titled “2. Check for Jakarta EE 10 Namespace”Spring Boot 3 has migrated from javax.* to jakarta.*. If you are using legacy annotations for dependency injection or lifecycle management, the scanner may ignore them.
Check your imports:
// ❌ WRONG (Spring Boot 2.x / J2EE)import javax.annotation.PostConstruct;
// ✅ CORRECT (Spring Boot 3.x / Jakarta EE)import jakarta.annotation.PostConstruct;import org.springframework.stereotype.Service;
@Servicepublic class BusinessService { /* ... */}3. Debug via Condition Evaluation Report
Section titled “3. Debug via Condition Evaluation Report”To see exactly why a bean was or wasn’t loaded, run the application with the --debug flag.
- Press Shift + F10 in IntelliJ or run via CLI:
Terminal window java -jar target/app.jar --debug - Search the console output for
CONDITIONS EVALUATION REPORT. - Look for your service class name. It will tell you if it was excluded by a
@Conditionalannotation or if the scan skipped that package.
4. Ensure Proper Injection Strategy
Section titled “4. Ensure Proper Injection Strategy”If your @Service is found but cannot be injected, ensure the consumer is also a Spring-managed bean. Never use new to instantiate a class that requires injection.
The “Elite” Standard (Constructor Injection):
@RestControllerpublic class MyController {
private final MyService myService;
// Spring Boot 3 automatically resolves this without @Autowired public MyController(MyService myService) { this.myService = myService; }}5. Clear AOT Generated Sources (For Native/GraalVM Users)
Section titled “5. Clear AOT Generated Sources (For Native/GraalVM Users)”If you recently attempted a native build using native-image, stale AOT generated classes in target/spring-aot might interfere with the standard JVM run.
Execute a clean build:
./mvnw clean compile🛡️ Prevention and Best Practices
Section titled “🛡️ Prevention and Best Practices”- Strict Package Hierarchy: Always place your
@SpringBootApplicationclass in the root package (e.g.,com.company.project) and all services/controllers in sub-packages. - Avoid
@ComponentScanOverrides: Relying on the default implicit scan is less error-prone than manually listing packages. - Use
@RequiredArgsConstructor: Use Lombok to handle constructor injection, ensuring allfinalfields are injected, which makes missing beans a compile-time awareness issue rather than a runtime failure. - Test Context Verification: Always include a basic context load test to catch bean definition errors during CI/CD:
@SpringBootTestclass ApplicationTests {@Testvoid contextLoads() {// Fails immediately if any @Service is missing}}