• 『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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 创建测试 Controller
    package com.lagou.controller;
    
    @RestController
    public class TestController {
    
    	@RequestMapping("/test")
    	public String test(){
    		System.out.println("源码环境构建成功...");
    		return "源码环境构建成功";
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    处理 @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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    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"));
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 其中,对于主类 com.lagou.SpringBootMytestApplication 所扫描的 import 类(分别是 @EnableAutoConfiguration 注解内的 AutoConfigurationImportSelector.classAutoConfigurationPackages.Registrar.class)如下
      在这里插入图片描述
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    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);
    					}
    				});
    			}
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 其中,groupings 属性示图如下,其中 group 属性为:org.springframework.boot.autoconfigure.AutoConfigurationImportSelector$AutoConfigurationGroup,而 deferredImports 属性为包含了主类 com.lagou.SpringBootMytestApplicationConfigurationClass,以及 org.springframework.boot.autoconfigure.AutoConfigurationImportSelector 对象
      在这里插入图片描述
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    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();
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 其中,selectImports() 返回如下
      在这里插入图片描述
    1. 总结
      在这里插入图片描述
  • 相关阅读:
    Docker
    GitHub 报告发布:TypeScript 取代 Java 成为第三受欢迎语言
    洛谷 P4568 [JLOI2011] 飞行路线(分层图最短路)
    安静的思考
    uni-app : 生成三位随机数、自定义全局变量、自定义全局函数、传参、多参数返回值
    EXCEL会计记账报表财务软件企业公司做账系统凭证自动生成报表
    【JavaScript】blob
    数据库死锁场景
    kafka消息发送者
    用Excel制作甘特图跟踪项目进度(附绘制教程)
  • 原文地址:https://blog.csdn.net/zzz805/article/details/132643277