@import是一个注解,专门用来导入实现了importSelector和importBeanDefinitionRegistrar接口的类,当然也可以用来导入普通的Bean。
@import的使用 @import+普通Beanpackage com.morris.spring.demo.annotation;
import com.morris.spring.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.import;
@import(User.class)
public class importSimpleBeanDemo {
@Test
public void testimportSingleBean() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(importSimpleBeanDemo.class);
User user = applicationContext.getBean(User.class);
System.out.println(user);
}
}
运行结果如下:
User(username=null, age=0)
可见User类上未加@Component注解,可以通过@import注解将User对象注入到Spring容器中。
@import+importSelectorimportSelectorBean实现了importSelector接口的selectimports()方法,该方法的返回值就是返回需要实例化的Bean的全限定名。
package com.morris.spring.entity.imports;
import org.springframework.context.annotation.importSelector;
import org.springframework.core.type.Annotationmetadata;
public class importSelectorBean implements importSelector {
@Override
public String[] selectimports(Annotationmetadata importingClassmetadata) {
return new String[]{"com.morris.spring.entity.User"};
}
}
importSelectorBeanDemo中使用了@import注解注入importSelector。
package com.morris.spring.entity.imports;
import org.springframework.context.annotation.importSelector;
import org.springframework.core.type.Annotationmetadata;
public class importSelectorBean implements importSelector {
@Override
public String[] selectimports(Annotationmetadata importingClassmetadata) {
return new String[]{"com.morris.spring.entity.User"};
}
}
运行结果如下:
User(username=null, age=0) false
可见User类上未加@Component注解,可以通过@import+importSelector将User对象注入到Spring容器中,但是importSelector对象本身并未被Spring管理。
@import+importBeanDefinitionRegistrarimportBeanDefinitionRegistrarBean实现了importBeanDefinitionRegistrar接口的registerBeanDefinitions()方法,该方法可以通过BeanDefinitionRegistry参数向容器中注入BeanDefinition,从而实现将Bean加入到Spring容器中。
package com.morris.spring.entity.imports;
import com.morris.spring.entity.User;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.importBeanDefinitionRegistrar;
import org.springframework.core.type.Annotationmetadata;
public class importBeanDefinitionRegistrarBean implements importBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(Annotationmetadata importingClassmetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
System.out.println(importingClassmetadata.getAnnotationTypes());
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
genericBeanDefinition.setBeanClass(User.class);
registry.registerBeanDefinition("user", genericBeanDefinition);
}
}
importBeanDefinitionRegistrarBeanDemo中使用了@import注解注入importBeanDefinitionRegistrarBean。
package com.morris.spring.demo.annotation;
import com.morris.spring.entity.User;
import com.morris.spring.entity.imports.importBeanDefinitionRegistrarBean;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.import;
@import(importBeanDefinitionRegistrarBean.class)
public class importBeanDefinitionRegistrarBeanDemo {
@Test
public void testimportSingleBean() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(importBeanDefinitionRegistrarBeanDemo.class);
User user = applicationContext.getBean(User.class);
System.out.println(user);
System.out.println(applicationContext.containsBean("importBeanDefinitionRegistrarBean"));
}
}
运行结果如下:
User(username=null, age=0) false
可见User类上未加@Component注解,可以通过@import+importBeanDefinitionRegistrar将User对象注入到Spring容器中,但是importBeanDefinitionRegistrar对象本身并未被Spring管理。
源码分析带着下面的问题进行分析:
importSelector和importBeanDefinitionRegistrar都是通过@import注解导入,那么@import注解所在的类是何时被扫描的?importSelector和importBeanDefinitionRegistrar接口的方法是何时被调用的?importSelector和importBeanDefinitionRegistrar对象为什么没有被加入到Spring容器中? @import的扫描
首先会从容器中取出所有的配置类(@Configuration、@Component、@ComponentScan、@import、@importResource、@Bean),因为这些类上面可能会有@import注解。
org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
// 先收集有@Configuration、@Component、@ComponentScan、@import、@importResource、@Bean的BD
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// 进来需要@Component、@ComponentScan、@import、@importResource、@Bean
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
... ...
获取类上面的@import注解:
org.springframework.context.annotation.ConfigurationClassParser#getimports
private Setgetimports(SourceClass sourceClass) throws IOException { Set imports = new linkedHashSet<>(); Set visited = new linkedHashSet<>(); collectimports(sourceClass, imports, visited); return imports; } private void collectimports(SourceClass sourceClass, Set imports, Set visited) throws IOException { if (visited.add(sourceClass)) { for (SourceClass annotation : sourceClass.getAnnotations()) { String annName = annotation.getmetadata().getClassName(); if (!annName.equals(import.class.getName())) { collectimports(annotation, imports, visited); } } imports.addAll(sourceClass.getAnnotationAttributes(import.class.getName(), "value")); } }
然后类上面有@import注解的才会调用processimports()方法。
org.springframework.context.annotation.ConfigurationClassParser#processimports
private void processimports(ConfigurationClass configClass, SourceClass currentSourceClass, CollectionimportCandidates, Predicate exclusionFilter, boolean checkForCircularimports) { if (importCandidates.isEmpty()) { return; } if (checkForCircularimports && isChainedimportOnStack(configClass)) { this.problemReporter.error(new CircularimportProblem(configClass, this.importStack)); } else { this.importStack.push(configClass); try { for (SourceClass candidate : importCandidates) { if (candidate.isAssignable(importSelector.class)) { // 处理importSelector // Candidate class is an importSelector -> delegate to it to determine imports Class> candidateClass = candidate.loadClass(); // 加载importSelector importSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, importSelector.class, this.environment, this.resourceLoader, this.registry); // 反射实例化importSelector Predicate selectorFilter = selector.getExclusionFilter(); if (selectorFilter != null) { exclusionFilter = exclusionFilter.or(selectorFilter); } if (selector instanceof DeferredimportSelector) { // 特殊处理DeferredimportSelector this.deferredimportSelectorHandler.handle(configClass, (DeferredimportSelector) selector); } else { // 调用selectimports方法 String[] importClassNames = selector.selectimports(currentSourceClass.getmetadata()); Collection importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); // 又递归,实际上会进入下面的else processimports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } } else if (candidate.isAssignable(importBeanDefinitionRegistrar.class)) { // Candidate class is an importBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions // 处理importBeanDefinitionRegistrar Class> candidateClass = candidate.loadClass(); // 实例化importBeanDefinitionRegistrar importBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, importBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry); // 这里只加入到configClass的importBeanDefinitionRegistrars容器中,并没有调用registerBeanDefinitions方法 // registerBeanDefinitions方法是在哪里调用的呢? configClass.addimportBeanDefinitionRegistrar(registrar, currentSourceClass.getmetadata()); } else { // Candidate class not an importSelector or importBeanDefinitionRegistrar -> // process it as an @Configuration class // 通过importSelector导入的类会进入这里,通过@import注入的普通类会进入这里 // 通过importSelector导入的类会从这里加入到importStack this.importStack.registerimport( currentSourceClass.getmetadata(), candidate.getmetadata().getClassName()); // 当成一个配置类来循环处理 processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter); } } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configClass.getmetadata().getClassName() + "]", ex); } finally { this.importStack.pop(); } } }
从上面的源码可以看出:
- importSelector会被直接反射实例化,然后调用selectimports()方法,将返回值放入到importStack中,注意importSelector本身没有被Spring容器所管理。然后又调用递归processimports方法,这样会进入本方法的else,当selectimports()导入的类当成一个配置类来处理。importBeanDefinitionRegistrar也会被直接反射实例化,然后加入到ConfigClass.importBeanDefinitionRegistrars属性中,importBeanDefinitionRegistrar.registerBeanDefinitions()此时并没有被调用。通过importSelector导入的类和通过@import注入的普通类会进入else代码块,当成一个配置类来循环处理,processConfigurationClass方法的最后一行会将所有的配置类加入到容器configurationClasses中。
那么configurationClasses中的配置类何时加入到Spring容器中呢?
importBeanDefinitionRegistrar.registerBeanDefinitions方法是在哪里调用的呢?
loadBeanDefinitionsorg.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions
public void loadBeanDefinitions(SetconfigurationModel) { TrackedConditionevaluator trackedConditionevaluator = new TrackedConditionevaluator(); for (ConfigurationClass configClass : configurationModel) { // 从配置类中加载BeanDefinition loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionevaluator); } } private void loadBeanDefinitionsForConfigurationClass( ConfigurationClass configClass, TrackedConditionevaluator trackedConditionevaluator) { if (trackedConditionevaluator.shouldSkip(configClass)) { String beanName = configClass.getBeanName(); if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) { this.registry.removeBeanDefinition(beanName); } this.importRegistry.removeimportingClass(configClass.getmetadata().getClassName()); return; } if (configClass.isimported()) { // 通过importSelector导入的类和通过@import注入的普通类在这里注入BeanDefinition registerBeanDefinitionForimportedConfigurationClass(configClass); } for (BeanMethod beanMethod : configClass.getBeanMethods()) { // 注入@Bean注解的BeanDefinition loadBeanDefinitionsForBeanMethod(beanMethod); } loadBeanDefinitionsFromimportedResources(configClass.getimportedResources()); // importBeanDefinitionRegistrar.registerBeanDefinitions的调用 loadBeanDefinitionsFromRegistrars(configClass.getimportBeanDefinitionRegistrars()); }
通过importSelector导入的类和通过@import注入的普通类在这里注入BeanDefinition
private void registerBeanDefinitionForimportedConfigurationClass(ConfigurationClass configClass) {
Annotationmetadata metadata = configClass.getmetadata();
AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
Scopemetadata scopemetadata = scopemetadataResolver.resolveScopemetadata(configBeanDef);
configBeanDef.setScope(scopemetadata.getScopeName());
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopemetadata, definitionHolder, this.registry);
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
configClass.setBeanName(configBeanName);
if (logger.isTraceEnabled()) {
logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
}
}
importBeanDefinitionRegistrar.registerBeanDefinitions()方法的调用:
private void loadBeanDefinitionsFromRegistrars(Mapregistrars) { // 调用importBeanDefinitionRegistrar.registerBeanDefinitions() registrars.forEach((registrar, metadata) -> registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator)); }



