Backend Development 8 min read

Why @Configuration Creates Proxies in Spring and Guarantees Singleton Beans

This article explains how Spring's @Configuration annotation triggers CGLIB proxy generation to manage @Bean methods, ensuring that internal calls return the same singleton instance, and contrasts this behavior with using @Component for configuration classes.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Why @Configuration Creates Proxies in Spring and Guarantees Singleton Beans

@Configuration is a class‑level annotation that marks a class as a source of bean definitions; methods annotated with @Bean declare beans, effectively replacing XML configuration and allowing flexible registration in the IoC container.

Simple Example

<code>static class Person {}

@Configuration
static class AppConfig {
    @Bean
    public Person person() {
        return new Person();
    }
}
</code>

Using @Component instead of @Configuration changes the behavior:

<code>@Component
static class AppConfig {
    @Bean
    public Person person() {
        return new Person();
    }
}

try (GenericApplicationContext context = new GenericApplicationContext()) {
    context.registerBean(AppConfig.class);
    System.out.println(context.getBean(Person.class));
}
</code>

When the class is annotated with @Configuration , multiple calls to person() return the same instance, while with @Component they return different instances, revealing the importance of the proxy mechanism.

How Spring Guarantees a Single Instance

Spring registers a ConfigurationClassPostProcessor , which is a BeanFactoryPostProcessor . It scans for @Configuration classes and marks them for proxy creation.

<code>// proxyBeanMethods = true means a proxy will be generated
@Configuration(proxyBeanMethods = true)
static class AppConfig {}
</code>

The marking is performed by ConfigurationClassUtils , which sets the attribute CONFIGURATION_CLASS_FULL (full) or CONFIGURATION_CLASS_LITE (lite) on the bean definition.

<code>if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
    beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
} else {
    beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
</code>

During postProcessBeanFactory , Spring enhances the marked configuration classes by generating a CGLIB subclass:

<code>public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
    // collect full‑configuration beans
    // create proxy subclass via ConfigurationClassEnhancer
    Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
    if (configClass != enhancedClass) {
        beanDef.setBeanClass(enhancedClass);
    }
}
</code>

The enhancer sets up callbacks, the most important being BeanMethodInterceptor :

<code>private static class BeanMethodInterceptor implements MethodInterceptor {
    public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] args, MethodProxy proxy) throws Throwable {
        ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
        String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
        return resolveBeanReference(beanMethod, args, beanFactory, beanName);
    }
}
</code>

This interceptor looks up the bean by name in the container and returns the existing singleton, so internal method calls never create a new instance.

Consequently, using @Configuration ensures that all @Bean methods are proxied and that the container always provides the same bean instance, whereas @Component lacks this proxying, leading to multiple instances.

In summary, Spring’s proxy‑based mechanism, driven by ConfigurationClassPostProcessor , ConfigurationClassUtils , and ConfigurationClassEnhancer , guarantees the singleton semantics of beans defined in @Configuration classes.

Did you learn something?

Finished!!!

JavaProxyconfigurationSpringBeanCglib
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

login 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.