Why Prefer @Bean Over @Component? Avoid Critical Spring Boot Pitfalls

The article explains the fundamental differences between @Component and @Bean in Spring Boot 3.5.0, demonstrates how @Bean provides finer control, solves five common configuration problems, and reveals a subtle proxy‑related bug that causes multiple bean instances when @Component is misused on configuration classes.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Why Prefer @Bean Over @Component? Avoid Critical Spring Boot Pitfalls

In Spring Boot 3.5.0, beans can be defined in three ways: component scanning with annotations such as @Component, explicit declaration with @Bean inside a configuration class, and the legacy XML approach. Scanning automatically registers simple beans, while @Bean offers precise control over creation, initialization, and dependency wiring.

Core Differences

@Component

is a class‑level annotation; any class marked with it (or its specializations like @Service, @Repository, @Controller) is discovered and registered as a bean by the container. @Bean is a method‑level annotation placed inside a class annotated with @Configuration, allowing the method to return a fully configured object.

@Component
public class MyBean {
    // ...
}
@Configuration
public class AppConfig {
    @Bean
    public MyBean myBean() {
        return new MyBean();
    }
}

Problems Solved by @Bean

Explicit Bean Configuration : When bean creation requires parameters or complex logic that cannot be expressed with simple annotation scanning.

Third‑Party Class Registration : Classes from external libraries (e.g., HikariDataSource) cannot be annotated with @Component, so they are defined with @Bean.

Custom Initialization : Allows conditional logic or custom code inside the method to set up the bean.

Reusability : Centralizes bean creation in configuration classes, making it easier to maintain and test.

Lazy Initialization : Can be combined with @Lazy to defer bean creation and improve startup time.

Configuration Example

@Configuration
public class DataSourceConfig {
    @Bean
    public DataSource customDataSource() {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ddd");
        dataSource.setUsername("root");
        dataSource.setPassword("xxxooo");
        // ...
        return dataSource;
    }
}

Because HikariDataSource cannot be marked with @Component, the @Bean method creates and returns a fully configured instance.

Dependency Injection

With @Component:

@Component
public class UserService {
    // field injection (not recommended)
    @Resource
    private UserRepository userRepository;
    // constructor injection (recommended)
    private final CommonService commonService;
    public UserService(CommonService commonService) {
        this.commonService = commonService;
    }
}

With @Bean:

@Configuration
public class Config {
    @Bean
    UserService userService(CommonService commonService) {
        return new UserService(commonService);
    }
}

Both approaches also support conditional injection via @ConditionalOnProperty:

@Bean
@ConditionalOnProperty(prefix = "pack.app", name = "enabled", havingValue = "true", matchIfMissing = false)
public UserService userService(CommonService commonService) { }

@Component
@ConditionalOnProperty(prefix = "pack.app", name = "enabled", havingValue = "true", matchIfMissing = false)
public class UserRepository { }

Bean Registration Pitfall

If a class is annotated with @Component and also declares @Bean methods, each call to a @Bean method creates a new instance because the class is treated as a regular object. The following output (first image) shows different instances being printed.

When the same class is changed to @Configuration, Spring creates a CGLIB proxy for the configuration class. Calls to @Bean methods are intercepted by BeanMethodInterceptor, which looks up the bean by name in the container and returns the singleton instance. The second image confirms that the same object is returned each time.

Thus, using @Configuration ensures that internal calls to @Bean methods are routed through the container, guaranteeing singleton semantics, whereas using @Component leads to ordinary method calls that instantiate new objects each time.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Configuration@ComponentSpring BootDependency Injection@Bean
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.