Foundation · Understand

Java Configuration (@Bean)

@Configuration and @Bean bring classes you do not own—SDK clients, clocks, mappers—under container lifecycle and injection control.

Primary source: Spring Framework 6.2 Reference: Java-based Container Configuration

20 min

Lesson 6 of 14

1d streak

The Architectural Question

You cannot annotate a class inside a third-party JAR with @Component; configuration classes are the sanctioned bridge into the container.

What this guide proves

  • @Configuration
  • @Bean
  • Third-party Beans

Full @Configuration vs Lite Mode: The CGLIB proxy divide

In Spring, Java-based configuration operates in one of two modes: Full Configuration Mode or Lite Configuration Mode. This distinction represents one of the most critical, yet frequently misunderstood, runtime mechanics in the entire framework.

ModeClass AnnotationProxy MechanismInter-Bean @Bean Call Semantics
Full Mode@Configuration (proxyBeanMethods = true, default)CGLIB subclass proxy generated at runtimeMethod calls intercepted: returns cached container singleton instance.
Lite Mode@Configuration(proxyBeanMethods = false) or @ComponentNo proxy (ordinary Java class)Method calls execute raw Java code: creates a NEW duplicate instance each call!

In Full mode, Spring generates a CGLIB subclass of your @Configuration class at startup. When one @Bean method calls another @Bean method (e.g. dataSource()), CGLIB intercepts the call, checks the BeanFactory singleton registry, and returns the existing managed singleton if already created. In Lite mode, no proxy exists, so calling the method simply invokes raw Java construction, producing duplicate instances!

When to use @Bean vs @Component

While @Component is ideal for classes whose source code you own, @Bean factory methods are essential in three production scenarios:

  1. 01Third-Party Library Classes: Configuring objects from external libraries (such as Jackson ObjectMapper, HikariDataSource, or RedisTemplate) where you cannot add @Component to the source code.
  2. 02Conditional / Programmatic Assembly: When instantiation requires algorithmic branching, environment evaluation, or dynamic parameters (e.g. constructing an in-memory client for dev and an OAuth2 client for prod).
  3. 03Explicit Lifecycle Control: Declaring custom init and destroy methods via @Bean(initMethod = "start", destroyMethod = "close").
InfrastructureConfig.java
@Configuration(proxyBeanMethods = true)
public class InfrastructureConfig {

    @Bean
    public ObjectMapper objectMapper() {
        return JsonMapper.builder()
            .findAndAddModules()
            .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
            .build();
    }

    @Bean
    public AuditClient auditClient(ObjectMapper mapper) { // Method parameter injection!
        return new AuditClient(mapper);
    }
}

Break it deliberately: Multiple instances in Lite mode

When developers use proxyBeanMethods = false (often to improve startup time or ahead-of-time compilation) and directly invoke other @Bean methods, they unknowingly violate singleton guarantees, creating multiple connection pools or caches.

DangerousLiteConfig.java
@Configuration(proxyBeanMethods = false) // Lite mode: CGLIB proxying is DISABLED!
public class DangerousLiteConfig {

    @Bean
    public ConnectionPool pool() {
        return new ConnectionPool(); // Costly resource!
    }

    @Bean
    public OrderService orderService() {
        return new OrderService(pool()); // Calls pool() directly!
    }

    @Bean
    public PaymentService paymentService() {
        return new PaymentService(pool()); // Calls pool() directly!
    }
}
Terminal / Diagnostic Output
// Output from ApplicationContext inspection:
OrderService pool hashcode:   ConnectionPool@7f31245a
PaymentService pool hashcode: ConnectionPool@2a1844b2
WARN: Two separate ConnectionPool instances created! Total database connections doubled!

The universal best practice

Never call an @Bean method directly from another @Bean method. Always declare dependencies as method parameters: @Bean PaymentService paymentService(ConnectionPool pool). Parameter injection works reliably in BOTH Full and Lite modes.

Check your understanding

Active Recall Checkpoint

What runtime mechanism allows Spring to intercept direct @Bean method calls in a @Configuration class to enforce singleton semantics?

Hint: Think about bytecode manipulation and dynamic subclassing.

Show answer & explanation

Spring generates a CGLIB subclass proxy of the @Configuration class when proxyBeanMethods = true. The proxy intercepts calls between @Bean methods, querying the container singleton registry before executing the method body.

Active Recall Checkpoint

Why should backend developers prefer declaring @Bean dependencies as method parameters rather than calling @Bean methods directly?

Hint: Consider portability between Full mode and Lite mode.

Show answer & explanation

Method parameter injection works identically in both Full and Lite (proxyBeanMethods = false) modes, ensuring that dependencies are always resolved from the container rather than invoking accidental duplicate constructors.

Synthesis & Production Verification

Production Acceptance Criteria

  • Expose a third-party type as a @Bean
  • Prove two injection points share one instance
  • Explain what proxyBeanMethods = false changes about intra-class calls

Architectural & Technical Review

Core Interview Questions

Q01What is the difference between Full @Configuration and Lite configuration mode in Spring?Show answer

Full mode (@Configuration with proxyBeanMethods = true) generates a runtime CGLIB subclass proxy that intercepts calls between @Bean methods to return the cached container singleton. Lite mode (@Component with @Bean or proxyBeanMethods = false) skips CGLIB proxying, executing raw Java method calls.

Q02Why should dependencies between @Bean methods always be declared as method parameters rather than calling @Bean methods directly?Show answer

Declaring dependencies as method parameters works uniformly in both Full and Lite modes. It avoids accidental duplicate instance creation when proxyBeanMethods = false and makes dependency relationships explicit to the container.

Q03What happens when an @Bean method directly invokes another @Bean method inside a class with proxyBeanMethods = false?Show answer

Because CGLIB proxying is disabled, the call executes as a normal Java method invocation on 'this', creating a new, unmanaged duplicate instance and violating singleton guarantees.

Production Pitfalls

Critical Anti-Patterns

  • Pitfall: Calling @Bean methods directly when proxyBeanMethods is false — In Lite mode, calling @Bean methods directly executes raw Java constructors, duplicating heavy resources like connection pools or client sessions.
  • Pitfall: Putting heavy business logic inside @Bean factory methods — Factory methods should configure and instantiate beans, not execute business workflows or database transactions during container startup.

Primary Documentation & Specifications

Supplementary Module Resources