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.
@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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
