Spring @Import注解源码分析

37 篇文章 0 订阅
29 篇文章 0 订阅

概述

Import注解Java doc

指示要导入的一个或多个组件类,通常为@Configuration类。

提供与Spring XML中的<import/>元素等效的功能。允许导入@Configuration类、ImportSelector和ImportBeanDefinitionRegistrar实现,以及常规组件类(自4.2起;类似于AnnotationConfigApplicationContext.register(java.lang.Class<?> …))。

导入的@Configuration类中声明的@Bean定义应该使用@Autowired注入来访问。要么bean本身可以是自动装配的,要么声明bean的配置类实例可以是自动装配的。

可以在类级别和MetaAnnotation声明。

如果是XML或其他非@Configuration类需要导入@Bean定义资源,可以使用@ImportResource注解。

这个注解需要传一个Class<?>[]参数:@Configuration、ImportSelector、ImportBeanDefinitionRegistrar或者其他常规组件类。

ImportSelector接口

实现类需要根据给定的Select条件(通常是一个或多个Annotation Attribute)确定应导入哪些@Configuration类。

实现类可以实现以下Aware接口,在调用selectImports之前,将会调用它们各自的Aware逻辑:

  • EnvironmentAware
  • BeanFactoryAware
  • BeanClassLoaderAware
  • ResourceLoaderAware

或者,该类可以为单个构造函数提供一个或多个以下支持的参数类型:

  • Environment
  • BeanFactory
  • ClassLoader
  • ResourceLoader

ImportSelector实现类通常以与常规@Import注解相同的方式进行处理,但是,也可以推迟Selector导入,即直到处理完所有@Configuration类,DeferredImportSelector接口可以实现这个功能。

该接口提供一个方法:

// Select and return the names of which class(es) should be imported based on 
// the AnnotationMetadata of the importing @Configuration class.
String[] selectImports(AnnotationMetadata importingClassMetadata)

DeferredImportSelector接口

继承ImportSelector接口。

ImportSelector的变体,在处理完所有@Configuration Bean之后运行。当导入为@Conditional时,这种类型的选择器可能特别有用。

实现类可以扩展Ordered接口或使用Order注释来指示相对于其他DeferredImportSelector的优先级。

getImportGroup方法需要返回一个DeferredImportSelector.Group的实现类Class对象,用于确定哪些类需要导入。

Group接口提供两个方法:

// Process the AnnotationMetadata of the importing @Configuration class 
// using the specified DeferredImportSelector.
process(AnnotationMetadata metadata, DeferredImportSelector selector)

// Return the entries of which class(es) should be imported for this group.
selectImports()

ImportBeanDefinitionRegistrar接口

该接口的实现类会在处理@Configuration类时向容器注册额外的Bean定义,当需要在Bean Definition阶段进行一些操作时,这个接口的实现类就很有用。

与@Configuration和ImportSelector一起使用,可以用ImportSelector的返回值向@Import注解提供此接口的实现类。

// Register bean definitions as necessary based on the given annotation metadata 
// of the importing @Configuration class.
default void registerBeanDefinitions(
    	AnnotationMetadata importingClassMetadata,
    	BeanDefinitionRegistry registry,
		BeanNameGenerator importBeanNameGenerator) {
	registerBeanDefinitions(importingClassMetadata, registry);
}

// Register bean definitions as necessary based on the given annotation metadata 
// of the importing @Configuration class.
default void registerBeanDefinitions(
    	AnnotationMetadata importingClassMetadata,
    	BeanDefinitionRegistry registry) {
}

基本流程

ConfigurationClassPostProcessor类

在@Bean注解解析中,介绍了AnnotationConfigApplicationContext创建时会注册几个注解驱动处理器,其中就包括ConfigurationClassPostProcessor类。

他是BeanDefinitionRegistryPostProcessor实现,用于解析@Configuration类,他是按优先级排序的,因为在@Configuration类中声明的任何Bean方法都必须在任何其他BeanFactoryPostProcessor执行之前注册其对应的BeanDefinition。

他在invokeBeanFactoryPostProcessors(beanFactory)阶段被调用,通过postProcessBeanDefinitionRegistry(registry)方法解析@Configuration类。

这个过程的源码在@Bean注解解析中记录过,此处不再记录。

调用到processConfigBeanDefinitions(registry)方法,其中有一段使用ConfigurationClassParser解析@Configuration类的代码,如下:

// 1. Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
		this.metadataReaderFactory, this.problemReporter, this.environment,
		this.resourceLoader, this.componentScanBeanNameGenerator, registry);

Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());

// 此处是一个do while循环
// 因为解析一遍之后,容器里面可能会有新的被注入的@Configuration Class定义,需要进一步解析
// 比如@Import注解就有可能注入新的@Configuration Class定义
do {
	parser.parse(candidates);
	parser.validate();

	Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
	configClasses.removeAll(alreadyParsed);

	// 2. Read the model and create bean definitions based on its content
	this.reader.loadBeanDefinitions(configClasses);

	// ...
} while (!candidates.isEmpty());

// ...

以上代码做了两件事:

  • Parse @Configuration class
  • 解析ConfigurationClass集注册BeanDefinition

Parse @Configuration class

public void parse(Set<BeanDefinitionHolder> configCandidates) {
	for (BeanDefinitionHolder holder : configCandidates) {
		BeanDefinition bd = holder.getBeanDefinition();
		try {
			if (bd instanceof AnnotatedBeanDefinition) {
				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("", ex);
		}
	}

	// DeferredImportSelector处理
	this.deferredImportSelectorHandler.process();
}

三个分支最终都会调用到processConfigurationClass方法,该方法会递归的分析一个ConfigurationClass及其父类,核心源码在以下这几行:

// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
	// 分析ConfigurationClass
	sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
} while (sourceClass != null);

this.configurationClasses.put(configClass, configClass);

doProcessConfigurationClass方法:

  1. 递归解析内部类

  2. 解析@PropertySource注解

  3. 解析@ComponentScan注解

  4. 解析@Import注解

    // Process any @Import annotations
    processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
    
  5. 解析@ImportResource注解

  6. 解析@Bean注解

  7. 获取父类用于递归解析

processImports方法解析@Import注解

该方法需要以下参数:

  1. ConfigurationClass configClass - 当前分析的@Configuration类
  2. SourceClass currentSourceClass - 这个参数与configClass不一样,configClass始终不变,是当前@Configuration类,而这个参数会随着递归解析父类而改变
  3. Collection<SourceClass> importCandidates - @Import注解导入类
  4. Predicate<String> exclusionFilter - 会过滤掉java.lang.annotation和org.springframework.stereotype下面的类
  5. boolean checkForCircularImports - 检测循环Import

代码:

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 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) {
			// 这个分支支持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)) {
		// 这个分支支持ImportBeanDefinitionRegistrar

		// 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 {
		// 这个分支支持@Configuration class

		// 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的逻辑:

// 调用selectImports方法获取导入的组件集
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
// 这里又递归调用了processImports方法
// 所以selectImports返回的类型可以是:普通@Configuration类、ImportSelector或者ImportBeanDefinitionRegistrar
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);

DeferredImportSelector支持

if (selector instanceof DeferredImportSelector) {
	this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();

/**
 * Handle the specified DeferredImportSelector.
 * If deferred import selectors are being collected, this registers this instance to the list.
 * If they are being processed,
 * the DeferredImportSelector is also processed immediately according to its DeferredImportSelector.Group.
 */
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
	DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
	if (this.deferredImportSelectors == null) {
		DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
		handler.register(holder);
		handler.processGroupImports();
	} else {
        // If deferred import selectors are being collected, this registers this instance to the list.
        // 等待解析了所有的@Configuration类之后再处理DeferredImportSelector
		this.deferredImportSelectors.add(holder);
	}
}

process核心逻辑:

public void processGroupImports() {
	for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
		Predicate<String> exclusionFilter = grouping.getCandidateFilter();
		grouping.getImports().forEach(entry -> {
			ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
			try {
				processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
						Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
						exclusionFilter, false);
			} catch (BeanDefinitionStoreException ex) {
				throw ex;
			} catch (Throwable ex) {
				throw new BeanDefinitionStoreException("", ex);
			}
		});
	}
}

// getImports方法
public Iterable<Group.Entry> getImports() {
	for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
		this.group.process(deferredImport.getConfigurationClass().getMetadata(),
				deferredImport.getImportSelector());
	}
	return this.group.selectImports();
}

ImportBeanDefinitionRegistrar支持

// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
// 实例化ImportBeanDefinitionRegistrar对象
ImportBeanDefinitionRegistrar registrar =
		ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
				this.environment, this.resourceLoader, this.registry);

// 添加到ConfigurationClass的importBeanDefinitionRegistrars集合
// 等待后续loadBeanDefinitions时会调用registerBeanDefinitions方法让开发者注册BeanDefinition
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());

普通@Configuration类

// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
		currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());

// 调用processConfigurationClass方法解析@Configuration class
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值