Java教程

spring源码之@Import

本文主要是介绍spring源码之@Import,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

@Import注解的作用为解析指定的class类,如果是简单的java类就直接作为一个bean放入容器中,如果是@Configuration就正常当做配置类解析,

如果实现了ImportSelector接口,就会调用selectImports接口方法将返回的字符串数组对应的class加载进容器并递归解析;

如果实现了ImportBeanDefinitionRegistrar接口,就会调用registerBeanDefinitions接口方法,通过这种方式可以自由的注册Bean到IOC容器中,mybatis的MapperScan注解就是通过这种方式扩展的

org.mybatis.spring.annotation.MapperScannerRegistrar,关于mybatis扩展的详细内容单独写一篇博文

 

 下面看下spring代码是怎么处理这段逻辑的,入口为下方这个BeanDefinitionRegistryPostProcessor:

org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

BeanDefinitionRegistryPostProcessor的调用入口在org.springframework.context.support.AbstractApplicationContext#refresh这里,详细的可以参考spring启动过程那篇博文:

 

该后处理bean能处理哪些bean?org.springframework.context.annotation.ConfigurationClassUtils#checkConfigurationClassCandidate给出了答案

 

 

 

 

 首先是要有Configuration注解,其次是看org.springframework.context.annotation.ConfigurationClassUtils#isConfigurationCandidate

 

 

 

 是的,就是处理有Configuration注解,并且至少有这四个注解中的一个Component、ComponentScan、Import、ImportResource

回到org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

 

 解析的核心方法为org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass

ComponentScan注解的处理:

 

 其他注解的处理:

 

 重点看到@Import注解的处理逻辑:

for (SourceClass candidate : importCandidates) {
      // ImportSelector注解处理逻辑
	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);
		}
                // 实现DeferredImportSelector接口的selector暂存放到最后处理,因为实现该接口的类通常会带有 @Conditional注解,只有等到其他所有
                // bean都加载完了才能确定是否要添加该bean,典型的就是springboot的自动装配selector:org.springframework.boot.autoconfigure.AutoConfigurationImportSelector
                // 典型的注解如ConditionalOnMissingBean
		if (selector instanceof DeferredImportSelector) {
			this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
		}
		else {
                        // 普通的ImportSelector就直接调用selectImports返回字符串数组,并递归解析这些class
			String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
			Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
			processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
		}
	}
        // 实现ImportBeanDefinitionRegistrar接口的selector会先实例化并把实例放入到configClass的importBeanDefinitionRegistrars中暂存
        // parse完回到后处理bean中,下方的ConfigurationClassBeanDefinitionReader会丛中注册beanDefinition
	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 {
                // 这里的英文注释很清楚了吧,都不是上面两种情况的话直接当做@Configuration处理
		// 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);
	}
}

org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass最后会把当前configClass放入集合

 

 parse完回到后处理bean:ConfigurationClassPostProcessor

 

 下面看下reader方法:

核心方法org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass

 

 至此,@Import方式扩展注册beanDefinition就基本都清晰了。

 

这篇关于spring源码之@Import的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!