提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


文章目录

  • 前言
  • 一、@Import 注解
  • 二、@Import的原理解析
  • 1.调用链
  • 2. @Import 与Aware的问题
  • 总结



前言

我们有许多的方式可以在spring 里加入BeanDefinition对象, 例如最常见的@Component,@Bean。
接下来我们介绍另外一种方式帮我们加入bean实例:@Import


提示:以下是本篇文章正文内容,下面案例可供参考

一、@Import 注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

	/**
	 * {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
	 * or regular component classes to import.
	 */
	Class<?>[] value();

}

源码十分简单,而且也写明了可以配合 Configuration , ImportSelector, ImportBeanDefinitionRegistrar 来进行使用。
接下来我们来看看简单的例子。

@Component
@Import(ImportAwareTest.class)
public class TestImportBean {

}

@Import支持导入普通的没有@Configuration注解的类,并将其实例化加入IOC容器中, 这里由实现了ImportAware接口,所以必须得加上@Component注解,否者setImportMetadata不会执行(至于为什么,后面会讲到)

@Component
public class ImportAwareTest implements ImportAware {
	@Override
	public void setImportMetadata(AnnotationMetadata importMetadata) {
		System.out.println("----importMetadata---------"+ importMetadata);
	}
}

@Import与ImportSelector配合,只需要将beanName 返回, 就可以讲该bean实例化加入IOC容器中。

public class ImportAwareTest implements ImportSelector {
	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		return new String[]{xxx.class};
	}
}

@Import与ImportBeanDefinitionRegistrar 配合,由于第二个参数传递的是BeanDefinitionRegistry ,那么直接可以对IOC容器的Bean对象进行增删改查了。

public class ImportAwareTest implements ImportBeanDefinitionRegistrar {
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		BeanDefinitionBuilder xxxService = BeanDefinitionBuilder.rootBeanDefinition(XXX.class);
		registry.registerBeanDefinition("xxxx", xxxService.getBeanDefinition());
	}
}

二、@Import的原理解析

1.调用链

SpringApplication.run(MyApplication.class, args) -> 
SpringApplication run(Object source, String... args) ->
SpringApplication run(Object[] sources, String[] args) ->
SpringApplication run(String... args) ->
SpringApplication refreshContext(ConfigurableApplicationContext context) ->
SpringApplication refresh(ApplicationContext applicationContext) -> 
EmbeddedWebApplicationContext refresh() -> 
AbstractApplicationContext refresh() ->
AbstractApplicationContext invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) ->
PostProcessorRegistrationDelegate invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) ->
//重点就在于ConfigurationClassPostProcessor
ConfigurationClassPostProcessor postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) ->
ConfigurationClassPostProcessor processConfigBeanDefinitions(BeanDefinitionRegistry registry) ->
ConfigurationClassParser parse(Set<BeanDefinitionHolder> configCandidates) ->
//这里有三个parse的方法,我们只取其中一个来进行分析
ConfigurationClassParser parse(AnnotationMetadata metadata, String beanName) ->
ConfigurationClassParser processConfigurationClass(ConfigurationClass configClass) ->
ConfigurationClassParser doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)

兜兜转转,终于到了本次讲解的重点代码。

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {
		//处理有@Component注解的类
		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
			processMemberClasses(configClass, sourceClass);
		}

		// Process any @PropertySource annotations
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			if (this.environment instanceof ConfigurableEnvironment) {
				processPropertySource(propertySource);
			}
			else {
				logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}

		// Process any @ComponentScan annotations
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				// The config class is annotated with @ComponentScan -> perform the scan immediately
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// Check the set of scanned definitions for any further config classes and parse recursively if needed
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}
		//本次的重点在这里,处理@Import注解
		// Process any @Import annotations
		processImports(configClass, sourceClass, getImports(sourceClass), true);

		// Process any @ImportResource annotations
		AnnotationAttributes importResource =
				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
		if (importResource != null) {
			String[] resources = importResource.getStringArray("locations");
			Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
			for (String resource : resources) {
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}

		// Process individual @Bean methods
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// Process default methods on interfaces
		processInterfaces(configClass, sourceClass);

		// Process superclass, if any
		if (sourceClass.getMetadata().hasSuperClass()) {
			String superclass = sourceClass.getMetadata().getSuperClassName();
			if (superclass != null && !superclass.startsWith("java") &&
					!this.knownSuperclasses.containsKey(superclass)) {
				this.knownSuperclasses.put(superclass, configClass);
				// Superclass found, return its annotation metadata and recurse
				return sourceClass.getSuperClass();
			}
		}

		// No superclass -> processing is complete
		return null;
	}
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
		
		if (importCandidates.isEmpty()) {
			return;
		}

		if (checkForCircularImports && isChainedImportOnStack(configClass)) {
			this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
		}
		else {
			this.importStack.push(configClass);
			try {
				for (SourceClass candidate : importCandidates) {
				    //Import 的类 是否实现了ImportSelector接口
					if (candidate.isAssignable(ImportSelector.class)) {
						// Candidate class is an ImportSelector -> delegate to it to determine imports
						Class<?> candidateClass = candidate.loadClass();
						//实例化bean,并调用各类Aware方法。
						ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
						ParserStrategyUtils.invokeAwareMethods(
								selector, this.environment, this.resourceLoader, this.registry);
						if (selector instanceof DeferredImportSelector) {
							this.deferredImportSelectorHandler.handle(
									configClass, (DeferredImportSelector) selector);
						}
						else {
						//假如Bean实现了ImportSelector接口,则在这里调用了selectImports方法
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
							//selectImports方法返回的是类的全限定名,递归调用processImports
							processImports(configClass, currentSourceClass, importSourceClasses, false);
						}
					}
					//Import 的类 是否实现了ImportBeanDefinitionRegistrar接口
					else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
						// Candidate class is an ImportBeanDefinitionRegistrar ->
						// delegate to it to register additional bean definitions
						Class<?> candidateClass = candidate.loadClass();
						//实例化bean,并调用各类Aware方法。
						ImportBeanDefinitionRegistrar registrar =
								BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
						ParserStrategyUtils.invokeAwareMethods(
								registrar, this.environment, this.resourceLoader, this.registry);
					    //将该类加入importBeanDefinitionRegistrars 容器中
					    //registerBeanDefinitions的调用不在这里。将在后面执行
						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());
						//递归,直到没有@Import发现
						processConfigurationClass(candidate.asConfigClass(configClass));
					}
				}
			}
			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();
			}
		}
	}


这里的主要流程: 1. 被Import 的类实现了ImportSelector接口,则执行selectImports方法。 2. 如果没有实现任何接口,则将该Import的类加入容器中。 3. 需要注意的是,类上可能有多层嵌套Import(如A类import B类,B类import C类),所以这里使用了递归。


ImportBeanDefinitionRegistrar的接口调用我们还没找到,接下来我们回到ConfigurationClassPostProcessorl类

ConfigurationClassPostProcessor processConfigBeanDefinitions(BeanDefinitionRegistry registry) ->
ConfigurationClassBeanDefinitionReader loadBeanDefinitions(Set<ConfigurationClass> configurationModel) ->
ConfigurationClassBeanDefinitionReader loadBeanDefinitionsForConfigurationClass(
			ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) ->
ConfigurationClassBeanDefinitionReader loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars)


ImportBeanDefinitionRegistrars这个Map是不是看起来似曾相似,对的,刚才的调用链中,spring将实现了ImportBeanDefinitionRegistrar的类,加入到了这个容器中。接下来的事情就显而易见了,直接foreach调用registerBeanDefinitions方法。

private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
		registrars.forEach((registrar, metadata) ->
				registrar.registerBeanDefinitions(metadata, this.registry));
	}

2. @Import 与Aware的问题

代码如下(示例):
之前说过了,被import的类如果实现了Aware接口,那么必须在类上加上@Component注解。这是为什么呢?
通过debug后发现,如果没有加上@Component注解,那么在beanDefinitionNames容器中没有找到该类。
后面有时间再查一下这个问题。


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容。