@Import
相关源码解析
加载解析@Import
注解位于BeanFactoryPostProcessor
处理的时候:
AbstractApplicationContext
的refresh
方法
-> invokeBeanFactoryPostProcessors(beanFactory);
-> PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
-> registryProcessor.postProcessBeanDefinitionRegistry(registry);
这里的registryProcessor
,我们指ConfigurationClassPostProcessor
ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(registry)
-> processConfigBeanDefinitions(registry)
:
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { //省略一些配置检查与设置的逻辑 //根据@Order注解,排序所有的@Configuration类 configCandidates.sort((bd1, bd2) -> { int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()); int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition()); return Integer.compare(i1, i2); }); // 创建ConfigurationClassParser解析@Configuration类 ConfigurationClassParser parser = new ConfigurationClassParser( this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry); //剩余没有解析的@Configuration类 Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates); //已经解析的@Configuration类 Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size()); do { //解析 parser.parse(candidates); parser.validate(); Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); configClasses.removeAll(alreadyParsed); // 生成类定义读取器读取类定义 if (this.reader == null) { this.reader = new ConfigurationClassBeanDefinitionReader( registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry()); } this.reader.loadBeanDefinitions(configClasses); alreadyParsed.addAll(configClasses); candidates.clear(); if (registry.getBeanDefinitionCount() > candidateNames.length) { //省略检查是否有其他需要加载的配置的逻辑 } } while (!candidates.isEmpty()); //省略后续清理逻辑 }
其中parser.parse(candidates)
的逻辑主要由org.springframework.context.annotation.ConfigurationClassParser
实现,功能是加载@Import
注解还有即系@Import
注解。reader.loadBeanDefinitions(configClasses);
的逻辑主要由org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader
的loadBeanDefinitionsForConfigurationClass
方法实现,功能是将上面解析的配置转换为BeanDefinition
就是Bean
定义。
1. 加载@Import
注解
org.springframework.context.annotation.ConfigurationClassParser
首先是parse
方法
public void parse(Set<BeanDefinitionHolder> configCandidates) { for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { if (bd instanceof AnnotatedBeanDefinition) { //这里的parse实际上就是调用下面即将分析的doProcessConfigurationClass parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); } } //最后处理所有的`DeferredImportSelector`,符合上面提到的`DeferredImportSelector`的功能 this.deferredImportSelectorHandler.process(); } @Nullable protected final SourceClass doProcessConfigurationClass( ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter) throws IOException { //处理`@Component`注解的MemberClass相关代码... //处理`@PropertySource`注解相关代码... //处理`@ComponentScan`注解相关代码... //处理`@Import`注解: processImports(configClass, sourceClass, getImports(sourceClass), filter, true); //处理`@ImportResource`注解相关代码... //处理`@Bean`注解相关代码... //处理接口方法相关代码... //处理父类相关代码... }
通过getImports
方法,采集相关的@Import
里面的类。
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException { Set<SourceClass> imports = new LinkedHashSet<>(); Set<SourceClass> visited = new LinkedHashSet<>(); //递归查询所有注解以及注解的注解是否包含@Import collectImports(sourceClass, imports, visited); return imports; } private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited) throws IOException { //记录是否已经扫描过这个类,如果扫描过就不重复添加,防止重复或者死循环 if (visited.add(sourceClass)) { for (SourceClass annotation : sourceClass.getAnnotations()) { String annName = annotation.getMetadata().getClassName(); //对于非@Import注解,递归查找其内部是否包含@Import注解 if (!annName.equals(Import.class.getName())) { collectImports(annotation, imports, visited); } } //添加@Import注解里面的所有配置类 imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value")); } }
采集好之后,就可以解析了。
2. 解析@Import
注解
解析的方法是:processImports
//在解析时,入栈,解析结束后,出栈,通过检查栈中是否有当前类,判断是否有循环依赖 private final ImportStack importStack = new ImportStack(); //记录所有的ImportBeanDefinitionRegistrar private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars = new LinkedHashMap<>(); //解析也是递归方法 private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter, boolean checkForCircularImports) { if (importCandidates.isEmpty()) { return; } //通过importStack检查循环依赖 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接口的实现类 Class<?> candidateClass = candidate.loadClass(); //创建这些Selector实例 ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry); //查看是否有过滤器 Predicate<String> selectorFilter = selector.getExclusionFilter(); if (selectorFilter != null) { exclusionFilter = exclusionFilter.or(selectorFilter); } //如果是DeferredImportSelector,则用deferredImportSelectorHandler处理 if (selector instanceof DeferredImportSelector) { this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); } else { //如果不是DeferredImportSelector,调用selectImports方法获取要加载的类全限定名称,递归调用本方法继续解析 String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // 处理ImportBeanDefinitionRegistrar接口的实现类 Class<?> candidateClass = candidate.loadClass(); //同样的,创建这些ImportBeanDefinitionRegistrar实例 ImportBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry); //放入importBeanDefinitionRegistrar,用于后面加载 configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { //处理@Configuration注解类,或者是普通类(直接生成Bean) //在栈加上这个类 this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); //递归回到doProcessConfigurationClass处理@Configuration注解类 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(); } } }
这样,所有的@Conditional
类相关的@Import
注解就加载解析完成了,这是一个大的递归过程。
3. 转换为BeanDefinition
注册到容器
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader
的loadBeanDefinitionsForConfigurationClass
方法:
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; } //对Import完成的,加载其Import的BeanDefinition if (configClass.isImported()) { registerBeanDefinitionForImportedConfigurationClass(configClass); } //加载@Bean注解的方法生成的Bean的Definition for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } //@ImportResource 注解加载的 loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); //加载ImportBeanDefinitionRegistrar加载的Bean的Definition loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); }
通过这里可以看出,为啥之前说@Bean
注解的Bean
会优先于ImportBeanDefinitionRegistrar
返回的Bean
加载。