『SpringBoot 源码分析』run() 方法执行流程:(4)刷新应用上下文-处理 @Import 注解

『SpringBoot 源码分析』run() 方法执行流程:(4)刷新应用上下文-处理 @Import 注解

  • 基于 2.2.9.RELEASE
  • 问题:当方法进行了注释标记之后,springboot 又是怎么注入到容器中并创建类呢?
  1. 首先创建测试主程序
package com.lagou;

@SpringBootApplication//标注在类上说明这个类是`SpringBoot`的主配置类
public class SpringBootMytestApplication{

	public static void main(String[] args) {
		SpringApplication.run(SpringBootMytestApplication.class, args);
	}
}
  1. 创建测试 Controller
package com.lagou.controller;

@RestController
public class TestController {

	@RequestMapping("/test")
	public String test(){
		System.out.println("源码环境构建成功...");
		return "源码环境构建成功";
	}
}

处理 @Import 注解

  1. 在上一篇当中只讲述了在 refreshContext() 时处理 @ComponentScan 的流程,这步来简单看看处理 @Import 的流程。首先断点要先跳过 com.lagou.config.MyDataSourceConfigcom.lagou.controller.TestControllerparse() 处理,直到 sourceClass 为主类 com.lagou.SpringBootMytestApplication
class ConfigurationClassParser {
	...
	@Nullable
	protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
			throws IOException {

		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
			processMemberClasses(configClass, sourceClass, filter);
		}

		// 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());
					}
				}
			}
		}

		// 1. 处理 @Import 注解
		processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
		...
		// No superclass -> processing is complete
		return null;
	}
}
  1. 在处理前首先要获取要 import 的类,所以会先找到注解内所有的 @Import 标记的类。其中 collectImports() 会递归去找注解内所有 @Import 的信息,然后返回
class ConfigurationClassParser {
	...
	private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
		// sourceClass 为 com.lagou.SpringBootMytestApplication
		Set<SourceClass> imports = new LinkedHashSet<>();
		Set<SourceClass> visited = new LinkedHashSet<>();
		// 1. 收集注解中的 import 类
		collectImports(sourceClass, imports, visited);
		// 3. 返回扫描出来的 imports 类
		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();
				// 2. 判断注解的名称是不是 Import,不是的继续递归查找
				if (!annName.equals(Import.class.getName())) {
					collectImports(annotation, imports, visited);
				}
			}
			imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
		}
	}
}
  • 其中,对于主类 com.lagou.SpringBootMytestApplication 所扫描的 import 类(分别是 @EnableAutoConfiguration 注解内的 AutoConfigurationImportSelector.classAutoConfigurationPackages.Registrar.class)如下
    『SpringBoot 源码分析』run() 方法执行流程:(4)刷新应用上下文-处理 @Import 注解_第1张图片
  1. processImports() 只是把类注册到 IOC 容器 beanDefinitionMap 中,但还没实际进行调用。实际调用在 DeferredImportSelectorHandler 里面执行(主要是调用 AutoConfigurationImportSelector.class 的方法)
class ConfigurationClassParser {
	
	private final DeferredImportSelectorHandler deferredImportSelectorHandler = new DeferredImportSelectorHandler();
	...
	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(
						"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
			}
		}
		// 1. 委派 ImportSelector 处理器调用 AutoConfigurationImportSelector 的组方法
		this.deferredImportSelectorHandler.process();
	}
}
  1. 接下来会获取 DeferredImportSelectorHolder 来执行 @Import 导入的类
class ConfigurationClassParser {
	...
	private class DeferredImportSelectorHandler {
		
		@Nullable
		private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
		...
		public void process() {
			List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
			this.deferredImportSelectors = null;
			try {
				if (deferredImports != null) {
					DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
					deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
					deferredImports.forEach(handler::register);
					// 1. 处理组 Imports 类
					handler.processGroupImports();
				}
			}
			finally {
				this.deferredImportSelectors = new ArrayList<>();
			}
		}
	}
}
  1. processGroupImports() 中,会遍历其中一个与 org.springframework.boot.autoconfigure.AutoConfigurationImportSelector 相关的DeferredImportSelectorGrouping
class ConfigurationClassParser {
	...
	private class DeferredImportSelectorGroupingHandler {
		...
		public void processGroupImports() {
			for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
				Predicate<String> exclusionFilter = grouping.getCandidateFilter();
				// 1. getImports() 获取导入的类
				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(
								"Failed to process import candidates for configuration class [" +
										configurationClass.getMetadata().getClassName() + "]", ex);
					}
				});
			}
		}
	}
}
  • 其中,groupings 属性示图如下,其中 group 属性为:org.springframework.boot.autoconfigure.AutoConfigurationImportSelector$AutoConfigurationGroup,而 deferredImports 属性为包含了主类 com.lagou.SpringBootMytestApplicationConfigurationClass,以及 org.springframework.boot.autoconfigure.AutoConfigurationImportSelector 对象
    『SpringBoot 源码分析』run() 方法执行流程:(4)刷新应用上下文-处理 @Import 注解_第2张图片
  1. 接下来,调用 getImports() 时,会遍历 groupings 属性中的 deferredImports 属性,然后交由对应的 group 类来处理。举例这里就是交给 org.springframework.boot.autoconfigure.AutoConfigurationImportSelector$AutoConfigurationGroup 来处理 org.springframework.boot.autoconfigure.AutoConfigurationImportSelector 对象的执行
class ConfigurationClassParser {
	...
	private static class DeferredImportSelectorGrouping {
		private final DeferredImportSelector.Group group;
		private final List<DeferredImportSelectorHolder> deferredImports = new ArrayList<>();
		...
		public Iterable<Group.Entry> getImports() {
			for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
				// 1. 其中,这次调用的 group 为 org.springframework.boot.autoconfigure.AutoConfigurationImportSelector$AutoConfigurationGroup。而 deferredImports 为包含 org.springframework.boot.autoconfigure.AutoConfigurationImportSelector 的对象
				this.group.process(deferredImport.getConfigurationClass().getMetadata(),
						deferredImport.getImportSelector());
			}
			return this.group.selectImports();
		}
	}
}
  1. 接下来就走到扫描获取自动装配类的过程当中了,这在 『SpringBoot 源码分析』自动配置 这一章就讲述过了,就不在这重复描述
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
	...
	private static class AutoConfigurationGroup
			implements DeferredImportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
			
		private final List<AutoConfigurationEntry> autoConfigurationEntries = new ArrayList<>();
		private final Map<String, AnnotationMetadata> entries = new LinkedHashMap<>();
		...
		// 这里用来处理自动配置类,比如过滤掉不符合匹配条件的自动配置类
		@Override
		public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
			Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
					() -> String.format("Only %s implementations are supported, got %s",
							AutoConfigurationImportSelector.class.getSimpleName(),
							deferredImportSelector.getClass().getName()));

			// 调用 getAutoConfigurationEntry() 方法得到自动配置类放入 autoConfigurationEntry 对象中 重点关注
			AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
					.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);

			// 又将封装了自动配置类的 autoConfigurationEntry 对象装进 autoConfigurationEntries 集合
			this.autoConfigurationEntries.add(autoConfigurationEntry);
			// 遍历刚获取的自动配置类
			for (String importClassName : autoConfigurationEntry.getConfigurations()) {
				// 这里符合条件的自动配置类作为 key,annotationMetadata作为值放进 entries 集合
				this.entries.putIfAbsent(importClassName, annotationMetadata);
			}
		}
	}
}
  1. 接下来执行 org.springframework.boot.autoconfigure.AutoConfigurationImportSelector$AutoConfigurationGroupselectImports(),就能看到所有的自动装配类,就导入进行来了
class ConfigurationClassParser {
	...
	private static class DeferredImportSelectorGrouping {
		private final DeferredImportSelector.Group group;
		private final List<DeferredImportSelectorHolder> deferredImports = new ArrayList<>();
		...
		public Iterable<Group.Entry> getImports() {
			for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
				// 其中,这次调用的 group 为 org.springframework.boot.autoconfigure.AutoConfigurationImportSelector$AutoConfigurationGroup。而 deferredImports 为包含 org.springframework.boot.autoconfigure.AutoConfigurationImportSelector 的对象
				this.group.process(deferredImport.getConfigurationClass().getMetadata(),
						deferredImport.getImportSelector());
			}
			// 1. 返回所有 AutoConfigurationImportSelector 扫描的自动装配类
			return this.group.selectImports();
		}
	}
}
  • 其中,selectImports() 返回如下
    『SpringBoot 源码分析』run() 方法执行流程:(4)刷新应用上下文-处理 @Import 注解_第3张图片
  1. 总结
    『SpringBoot 源码分析』run() 方法执行流程:(4)刷新应用上下文-处理 @Import 注解_第4张图片

你可能感兴趣的:(『后端』,spring,boot,java,后端)