Skip to content

How to fix: Spring Boot 3 fails to find bean despite @Service annotation and correct package structure

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.

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.

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.java
com.project.service.MyService.java (Sibling - NOT scanned by default)

Correct Structure:

com.project.app.Application.java
com.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);
}
}

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;
@Service
public class BusinessService {
/* ... */
}

To see exactly why a bean was or wasn’t loaded, run the application with the --debug flag.

  1. Press Shift + F10 in IntelliJ or run via CLI:
    Terminal window
    java -jar target/app.jar --debug
  2. Search the console output for CONDITIONS EVALUATION REPORT.
  3. Look for your service class name. It will tell you if it was excluded by a @Conditional annotation or if the scan skipped that package.

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):

@RestController
public 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:

Terminal window
./mvnw clean compile
  1. Strict Package Hierarchy: Always place your @SpringBootApplication class in the root package (e.g., com.company.project) and all services/controllers in sub-packages.
  2. Avoid @ComponentScan Overrides: Relying on the default implicit scan is less error-prone than manually listing packages.
  3. Use @RequiredArgsConstructor: Use Lombok to handle constructor injection, ensuring all final fields are injected, which makes missing beans a compile-time awareness issue rather than a runtime failure.
  4. Test Context Verification: Always include a basic context load test to catch bean definition errors during CI/CD:
    @SpringBootTest
    class ApplicationTests {
    @Test
    void contextLoads() {
    // Fails immediately if any @Service is missing
    }
    }