spring @Import介绍

文档翻译

指示要导入的一个或多个组件类——通常是@Configuration类。
提供与 Spring XML 中<import/>元素等效的功能。允许导入@Configuration类、 ImportSelector和ImportBeanDefinitionRegistrar实现,以及常规组件类(从 4.2 开始;类似于AnnotationConfigApplicationContext.register )

何时解析@Import

答:处理配置类时。具体代码分析如下:
ConfigurationClassParser#processConfigurationClass会调用
ConfigurationClassParser#doProcessConfigurationClass方法
, 在doProcessConfigurationClass中如下代码处理:(这一块属于ConfigurationClassPostProcessor相关的,这里不做介绍,简单可理解为扫描出的bean都会经过此处代码处理)

		// Process any @Import annotations
		processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

getImports就是递归查找sourceClass上的@Import注解的值,就不展开看了,只看处理方法processImports。

processImports 处理@Import

				for (SourceClass candidate : importCandidates) {
					if (candidate.isAssignable(ImportSelector.class)) {
						// Candidate class is an ImportSelector -> delegate to it to determine imports
						Class<?> candidateClass = candidate.loadClass();
						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);
						}
						if (selector instanceof DeferredImportSelector) {
							this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
						}
						else {
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
							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
						Class<?> candidateClass = candidate.loadClass();
						ImportBeanDefinitionRegistrar registrar =
								ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
										this.environment, this.resourceLoader, this.registry);
						configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
					}
					else {
						// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
						// process it as an @Configuration class
						this.importStack.registerImport(
								currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
						processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
					}
				}
  • 候选类是一个ImportSelector,委托给ImportSelector以确定导入(导入其它bean)
  • 候选类是一个ImportBeanDefinitionRegistrar,委托给ImportBeanDefinitionRegistrar注册其他bean定义
  • 候选类不是ImportSelector或ImportBeanDefinitionRegistrar,将其作为@Configuration类处理。

ImportSelector处理

这里分为两种情况做了处理。

  • DeferredImportSelector(延期的的ImportSelector):ImportSelector的一种变体,在处理完所有@Configuration bean 后运行。当所选导入是@Conditional时,这种类型的选择器可能特别有用。
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

EnableAutoConfiguration上的 AutoConfigurationImportSelector就是这种类型。都说了在处理完所有@Configuration bean后才出处理DeferredImportSelector,所以这里的处理目前也很简单,就是包装了下放到了一个list集合中,真正的处理后续文章会说明(springboot starter)。(简化后代码)

		public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
			DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
			this.deferredImportSelectors.add(holder);
		}
  • 非DeferredImportSelector类型处理方式:调用importSelector接口方法selectImports()结果作为importSourceClasses ,然后又重新调用processImports 方法递归处理。这里有一点可以注意下,就是实例化ImportSelector代码,selectImports()实现里可以添加扩展。

ImportBeanDefinitionRegistrar处理

存入ConfigurationClass属性Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars中,后续会做真正的处理。处理就在ConfigurationClassPostProcessor#processConfigBeanDefinitions方法中。

this.reader.loadBeanDefinitions(configClasses);

@Configuration类型处理

Configuration处理会调用ConfigurationClassParser#processConfigurationClass,文章开头红色标识的。是的又开始了新一轮的循环。这里只是作为@Configuration类型处理,并不是说这个类上非得加上@Configuration注解,普通的bean也是可以的。只不过后续的解析过程中没有解析到@Import、@Bean等 而已

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值