How Does Spring’s @Enable Annotation Work Under the Hood?

This article explains the internal mechanics of Spring's @Enable annotations, detailing how they rely on @Import, the role of ConfigurationClassPostProcessor, the parsing flow of configuration classes, and how CGLIB enhances @Configuration classes to manage @Bean method invocations.

Programmer DD
Programmer DD
Programmer DD
How Does Spring’s @Enable Annotation Work Under the Hood?

@Enable Driving Logic

In everyday development we often use annotations such as @EnableEurekaClient, @EnableFeignClients, @EnableCircuitBreaker, and @EnableHystrix. All of them start with @Enable but implement different functions; this article explores how Spring resolves the @Enable logic.

Finding the Entry Point

@Enable modules are driven by @Import, which can import @Configuration classes, ImportSelector implementations, or ImportBeanDefinitionRegistrar implementations.

During the XML era, @Import was commonly used together with @Import, <context:component-scan> and <context:annotation-config>.

The mapping between XML schema namespaces and handlers is defined in /META-INF/spring.handlers on the classpath.

public class ContextNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        //省略其他代码
        registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
    }
}

The AnnotationConfigBeanDefinitionParser is the entry point we need to follow.

Finding the Core Class

Starting from AnnotationConfigBeanDefinitionParser.parse , the process eventually registers ConfigurationClassPostProcessor , which is the core class handling @Enable logic.

ConfigurationClassPostProcessor registers ConfigurationClassUtils and parses candidate beans, ultimately creating BeanDefinition objects for configuration classes.

Key responsibilities of ConfigurationClassPostProcessor: Sort candidates by @Order value. Parse @Configuration classes into ConfigurationClass objects. Read ConfigurationClass information and create BeanDefinition objects. Register ImportRegistry as a bean to support @Import‑aware @Configuration classes.

Core Method: processConfigBeanDefinitions

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    String[] candidateNames = registry.getBeanDefinitionNames();
    for (String beanName : candidateNames) {
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
            ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
            // already processed
        } else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }
    if (configCandidates.isEmpty()) {
        return;
    }
    // sort by @Order
    configCandidates.sort((bd1, bd2) -> {
        int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
        int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
        return Integer.compare(i1, i2);
    });
    // further processing … (omitted for brevity)
}

The method sorts candidates, parses them with ConfigurationClassParser , registers bean definitions, and finally registers the ImportRegistry bean.

Enhancing @Configuration Classes

Spring generates a CGLIB subclass for each @Configuration class. Each @Bean method is overridden in the subclass; the first call creates the bean instance, subsequent calls return the already created bean by name, ensuring proper scoping.

Excerpt from ConfigurationClassEnhancer Javadoc: "Enhances Configuration classes by generating a CGLIB subclass which interacts with the Spring container to respect bean scoping semantics for @Bean methods. Each @Bean method is overridden, delegating to the container when a new instance is required, otherwise returning the existing bean."

Summary

ConfigurationClassPostProcessor filters @Component, @Configuration, and @Bean definitions.

ConfigurationClassParser parses candidate bean definitions into ConfigurationClass objects, which are then turned into BeanDefinition objects by ConfigurationClassBeanDefinitionReader.

Parsing order: @PropertySource → @ComponentScan → @Import → @ImportResource → @Bean → default methods on interfaces → superclass processing.

@Configuration classes use the "full" mode; @Component and @Bean use the "lite" mode.

CGLIB enhances @Configuration classes so that each @Bean method is proxied, creating the bean once and returning the same instance on subsequent calls.

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.

JavaConfigurationannotationenable
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

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.