前言
imports是一个在spring体系里非常重要的注解,基本每个Enable开头的注解必然有一个import注解。接下来我们深入研究下import的作用。看小节的同学建议先取看PostProcessorRegistrationDelegate与BeanFactoryPostProcessor体系和AnnotationConfigUtils
PS: 可以先看这个博客了解下Spring Import 三种用法与源码解读
解析
ConfigurationClassParser的processImports方法是最核心的方法
// 这里是从SourceClass获得imports注解,注意jdk8允许标记多个注解,一个class可以标记多个不同注解,其他注解上也可以标记imports注解,所以需要一个set存放
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
Set<SourceClass> imports = new LinkedHashSet<>();
Set<SourceClass> visited = new LinkedHashSet<>();
collectImports(sourceClass, imports, visited);
return imports;
}
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,Collection<SourceClass> importCandidates,boolean checkForCircularImports) throws IOException {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports &&
this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass,
this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
// 看注解里面的类是不是ImportSelector的实现类
if (candidate.isAssignable(ImportSelector.class)) {
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
invokeAwareMethods(selector);
// 判断是否是需要延迟加载,继承DeferredImportSelector类的都会延迟加载
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
this.deferredImportSelectors.add(new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
}
else {
// 执行ImportSelector的实现类,返回需要加载的内容
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// 这个是非常重要的,ImportBeanDefinitionRegistrar.addImportBeanDefinitionRegistrar方法的形参是registrar。
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =BeanUtils.instantiateClass(candidateClass,ImportBeanDefinitionRegistrar.class);
invokeAwareMethods(registrar);
configClass.addImportBeanDefinitionRegistrar(registrar,
currentSourceClass.getMetadata());
}
else {
//
如果都不是,就调动processConfigurationClass(迭代了,processImports上两级的调用就是
processConfigurationClass)
this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Exception ex) {
throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
重点
ImportSelector
看ImportSelector.selectImports 就知道返回一个字符串数组,字符串数组是class的完全限定名,进行processImports扫描
public interface ImportSelector {
String[] selectImports(AnnotationMetadata importingClassMetadata);
}
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
ImportBeanDefinitionRegistrar
ImportBeanDefinitionRegistrar的重要行比ImportSelector高,最重要的是形参 BeanDefinitionRegistry,从下面代码BeanPostProcessorsRegistrar对象可以看 到,ImportBeanDefinitionRegistrar具备向容器里面注册bean的能力。可以添加想要的bean,完成想要的功能。
public interface ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}
public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws
BeansException {
if (beanFactory instanceof ConfigurableListableBeanFactory) {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
}
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {
if (this.beanFactory == null) {
return;
}
registerSyntheticBeanIfMissing(registry,"webServerFactoryCustomizerBeanPostProcessor",WebServerFactoryCustomizerBeanPostProcessor.class);
registerSyntheticBeanIfMissing(registry,"errorPageRegistrarBeanPostProcessor",ErrorPageRegistrarBeanPostProcessor.class);
}
private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry,String name, Class<?> beanClass) {
if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
beanDefinition.setSynthetic(true);
registry.registerBeanDefinition(name, beanDefinition);
}
}
}
得到ImportBeanDefinitionRegistrar不会立即执行,会保存到一个集合中,一起执行
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass,
ImportBeanDefinitionRegistrar.class);
invokeAwareMethods(registrar);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
public void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar, AnnotationMetadata importingClassMetadata) {
this.importBeanDefinitionRegistrars.put(registrar, importingClassMetadata);
}
执行时机,是等待所以初始化的注解或者class解析完成
只有一次出发机会
ConfigurationClassPostProcessor对象只会被执行一次,这次只会解析那些内容。请看下面的代码,只会解析UserConsumeApplication.class的所有注解,所以有一些imports注解是不会被扫描,执行到的。自己也被坑过一次,以为自己的imports会被扫描并且执行,搞了好久,真坑啊。
@SpringBootApplication
public class UserConsumeApplication {
public static void main(String[] args) {
SpringApplication.run(UserConsumeApplication.class, args);
}
}
#######
坐在一个很小的公园的花坛上写完。
来源:oschina
链接:https://my.oschina.net/u/1261452/blog/3109197