Deep Dive into Spring’s @Import: Usage, Three Scenarios, and Internal Mechanics
This article explains Spring's @Import annotation, compares it to @Bean, demonstrates three distinct usage patterns with concrete code examples, and walks through the underlying processing performed by ConfigurationClassPostProcessor and related internal methods.
1. Overview
The @Import annotation is a core part of Spring's Java‑based configuration. It works similarly to @Bean by injecting classes into the Spring container and provides the same functionality as certain XML elements. Its definition contains a single attribute Class<?>[] value() that holds an array of class objects.
2. Three Usage Patterns of @Import
Ordinary class
Class implementing ImportSelector (used by Spring Boot auto‑configuration)
Class implementing
ImportBeanDefinitionRegistrar2.1 Importing an Ordinary Class
Define a simple POJO, e.g., Student, and import it via a configuration class:
@Data
public class Student {
private Long id;
private String name;
private Integer age;
} @Configuration
@Import({Student.class})
public class MyConfig {
@Bean
public Person person01() {
return Person.builder().id(1L).name("shepherd").age(25).build();
}
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
for (String beanName : ctx.getBeanDefinitionNames()) {
System.out.println(beanName);
}
}
}Running the main() method prints internal Spring beans plus myConfig, the fully‑qualified name of Student, and the bean name person01. The bean name for an imported class defaults to its fully‑qualified class name, whereas a bean defined with @Bean uses the method name.
2.2 Importing a Class that Implements ImportSelector
This is the most common pattern, especially in Spring Boot auto‑configuration. The ImportSelector interface defines String[] selectImports(AnnotationMetadata) and an optional Predicate<String> getExclusionFilter().
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.shepherd.common.config.Student", "com.shepherd.common.config.Person"};
}
}Use it in a configuration class:
@Configuration
@Import({MyImportSelector.class})
public class MyConfig {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
for (String beanName : ctx.getBeanDefinitionNames()) {
System.out.println(beanName);
}
}
}The output shows the two classes returned by selectImports (Student and Person) added to the container, confirming that the selector drives the import process.
2.3 Importing a Class that Implements ImportBeanDefinitionRegistrar
Implementations of ImportBeanDefinitionRegistrar register bean definitions directly with the registry.
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(Person.class);
AbstractBeanDefinition beanDef = builder.getBeanDefinition();
String beanName = importBeanNameGenerator.generateBeanName(beanDef, registry);
registry.registerBeanDefinition(beanName, beanDef);
}
}Replace the configuration class import with @Import({MyImportBeanDefinitionRegistrar.class}) and the result is identical to the previous example, demonstrating that the registrar can programmatically create bean definitions.
3. Internal Implementation of @Import
The processing of @Import is performed by ConfigurationClassPostProcessor, a BeanFactoryPostProcessor that scans configuration classes. Its entry point is postProcessBeanDefinitionRegistry(), which delegates to processConfigBeanDefinitions(). Within that method, the parser iterates over candidate bean definitions, identifies configuration classes, and invokes processImports() for each @Import annotation.
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// ... checks omitted ...
processConfigBeanDefinitions(registry);
}The core import handling resides in processImports():
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
if (importCandidates.isEmpty()) return;
// circular import check omitted
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// instantiate selector, apply exclusion filter, call selectImports()
} else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// instantiate registrar and store for later registration
} else {
// treat as a regular @Configuration class
}
}
}The method distinguishes three cases exactly as described in the usage section: (1) classes implementing ImportSelector, (2) classes implementing ImportBeanDefinitionRegistrar, and (3) ordinary classes treated as configuration classes. After recursion, the collected configuration classes and registrars are handed to ConfigurationClassBeanDefinitionReader to load bean definitions into the container.
4. Summary
Overall, @Import relies on ConfigurationClassPostProcessor to parse and register imported classes. Understanding the three import mechanisms and the underlying processing flow is essential for advanced Spring configuration and for developing custom auto‑configuration modules.
Project Recommendation: A Spring Boot 2.x / Spring Cloud / Spring Cloud Alibaba enterprise framework (GitHub: https://github.com/plasticene/plasticene-boot-starter-parent, Gitee: https://gitee.com/plasticene3/plasticene-boot-starter-parent).
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.
Shepherd Advanced Notes
Dedicated to sharing advanced Java technical insights, daily work snippets, and the power of persistent effort.
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.
