SpringBoot 自动装配源码解析

SpringBoot 自动装配原理解析

该文基于2.0.5.RELEASE版本解析,该文会忽略不相关的源码内容,只关注相关自动装配源码, 关于SpringBoot启动流程源码,麻布会找个时间更新一期

启动类

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

实例化 AppicationContext

public ConfigurableApplicationContext run(String... args) {
		//...忽略相关代码
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			//此处会初始化我们的熟悉的ApplicationContext实例
			context = createApplicationContext();
			
		}
		//...忽略相关代码
		return context;
}

追踪源码, 定位到SpringApplication.run(String… args) 里, 我们看到在ApplicationContext即将被实例化,我们继续往下看


protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, "
								+ "please specify an ApplicationContextClass",
						ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

SpringBoot 在初始化前会查看应用的上下文是否存在SpringMVC相关依赖,存在将初始化
AnnotationConfigServletWebServerApplicationContext
我们追踪其构造方法

public AnnotationConfigServletWebServerApplicationContext() {
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
}

我们继续追踪 AnnotatedBeanDefinitionReader 构造方法进行查看

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
		this(registry, getOrCreateEnvironment(registry));
}

继续追踪

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(environment, "Environment must not be null");
		this.registry = registry;
		//用于处理 @ConditionalOnBean @ConditionalOnClass 
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		//为IOC容器注册相关的后置处理器   
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

此时自动装配的第一个关键点来了,我们把目光追踪到 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry) 方法中

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		//...忽略相关代码

		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
		
		/**
		检查IOC容器是否有注册名称为
			org.springframework.context.annotation.internalConfigurationAnnotationProcessor的Bean
		**/
		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			//如果不存在, 创建RootBeanDefinition
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			//往IOC容器注册 ConfigurationClassPostProcessor
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		//...忽略相关代码

		return beanDefs;
}
	
	
	
private static BeanDefinitionHolder registerPostProcessor(
		BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
		
	definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	//往IOC容器注册 BeanDefinition 
	registry.registerBeanDefinition(beanName, definition);
	return new BeanDefinitionHolder(definition, beanName);
}

此时注册了ConfigurationClassPostProcessor 到IOC容器, 我们查看该类的的继承关系:

在这里插入图片描述
在继承关系里我们看到它实现了 BeanDefinitionRegistryPostProcessor
明白Spring的IOC容器初始化原理的朋友都知道,IOC容器在启动后会优先先加载容器中的后置处理器,并执行后置处理器的方法,我们来回顾下IOC容器的初始化源码:


public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
			
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// 容器初始化前的准备工作
			prepareRefresh();

			// 初始化 DefaultListableBeanFactory
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 为beanFactory设置容器特性,例如类加载器、事件处理器等
			prepareBeanFactory(beanFactory);

			try {
				//空实现,为容器的某些子类指定特殊的beanPost事件处理器
				postProcessBeanFactory(beanFactory);

				//调用所有注册的BeanFactoryPostProcessor的bean
				invokeBeanFactoryPostProcessors(beanFactory);

				//将BeanPostProcessor后置处理器的bean追加到BeanFactory的Bean后置处理器列表中,用于触发bean的生命周期
				registerBeanPostProcessors(beanFactory);

				//初始化信息源,和国际化相关
				initMessageSource();


				//初始化容器事件传播器
				initApplicationEventMulticaster();

				//调用子类的某些特殊bean初始化方法
				onRefresh();

				//为事件传播器注册事件监听器
				registerListeners();

				//初始化所有剩余的单例bean
				finishBeanFactoryInitialization(beanFactory);


				//初始化容器的生命周期时间处理器,并发布容器的生命周期事件
				finishRefresh();
			}

			catch (BeansException ex) {
				//...忽略相关代码
			}

			finally {
				//...忽略相关代码
			}
		}
	}

}



我们可以看到 在BeanFactory初始化后,会先执行
invokeBeanFactoryPostProcessors() ,里面的主要逻辑是把BeanFactory里注册的 BeanBeanFactoryPostProcessor 类型的bean优先实例化并进行调用,

ConfigurationClassPostProcessor
该后置处理器的作用是修改IOC容器中的元数据, SpringBoot就是在此加载自动装配类注册到IOC容器中, 接下来我们将目光移到 ConfigurationClassPostProcessor

ConfigurationClassPostProcessor

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	//为入参的IOC容器生成唯一的id
	int registryId = System.identityHashCode(registry);
	//如果处理过了,则抛异常
	if (this.registriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
	}
	//如果处理过了,则抛异常
	if (this.factoriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanFactory already called on this post-processor against " + registry);
	}
	//追加处理过的标识
	this.registriesPostProcessed.add(registryId);
	//开始进行自动装配类的加载
	processConfigBeanDefinitions(registry);
}

我们直接定位 postProcessBeanDefinitionRegistry 方法中,修改IOC容器元数据入口在该方法内,在入口处对重复加载会抛异常,继续追踪 processConfigBeanDefinitions


public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		//缓存拥有@Configuration注解的bean
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		//获取容器中所有已注册的bean名称
		String[] candidateNames = registry.getBeanDefinitionNames();
		
		//遍历所有bean
		for (String beanName : candidateNames) {
			//得到 BeanDefinition
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			//检查 BeanDefinition 是否有包含configurationClass属性的值,有值证明已处理过,则忽略加入缓存
			if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
					ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
				}
			}
			//检查 BeanDefinition 的目标类是否包含@Configuration 注解
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				//追加到缓存中
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		// 缓存为空 则忽略
		if (configCandidates.isEmpty()) {
			return;
		}

		// 进行排序
		configCandidates.sort((bd1, bd2) -> {
			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
			return Integer.compare(i1, i2);
		});

		// 从容器中获取自定义的bean名称生成策略
		SingletonBeanRegistry sbr = null;
		if (registry instanceof SingletonBeanRegistry) {
			sbr = (SingletonBeanRegistry) registry;
			if (!this.localBeanNameGeneratorSet) {
				BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
				if (generator != null) {
					this.componentScanBeanNameGenerator = generator;
					this.importBeanNameGenerator = generator;
				}
			}
		}
		
		/**
			如果环境变量为空,则进行初始化,但SpringBoot在初始化 ApplicationContext 之前会初始化Environment ,
			并注入到ApplicationContext中,所以下面的条件不会成立
		**/
		if (this.environment == null) {
			this.environment = new StandardEnvironment();
		}

		// 初始化 @Configuration 注解处理器
		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 {
			//重点关注该方法,自动装配类的加载在里面完成
			parser.parse(candidates);
			//校验工作
			parser.validate();
			//把加载的装配类放到Set中
			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
			//删除已处理过的自动装配类
			configClasses.removeAll(alreadyParsed);

			// 初始化 自动装配类的bean读取器 ConfigurationClassBeanDefinitionReader
			if (this.reader == null) {
				this.reader = new ConfigurationClassBeanDefinitionReader(
						registry, this.sourceExtractor, this.resourceLoader, this.environment,
						this.importBeanNameGenerator, parser.getImportRegistry());
			}
			
			/**
				主要逻辑是把装配类的所有被@Bean修饰的方法转换成 ConfigurationClassBeanDefinition 并注册到IOC
			**/
			this.reader.loadBeanDefinitions(configClasses);
			//追加到处理过的自动装配类缓存中
			alreadyParsed.addAll(configClasses);
			//清空要处理的自动装配类缓存
			candidates.clear();
			
			//如果此时IOC容器注册的bean数量大于加载装配类前缓存的bean数量,说明成功注册了新的 BeanDefinition 到IOC容器中
			if (registry.getBeanDefinitionCount() > candidateNames.length) {
				//IOC容器最新bean名称集合
				String[] newCandidateNames = registry.getBeanDefinitionNames();
				//老的bean名称集合
				Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
				//初始化处理过的装配类集合
				Set<String> alreadyParsedClasses = new HashSet<>();
				for (ConfigurationClass configurationClass : alreadyParsed) {
					alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
				}
				
				//遍历IOC容器最新bean名称集合
				for (String candidateName : newCandidateNames) {
					//如果老的bean名称集合不包含最新的bean名称
					if (!oldCandidateNames.contains(candidateName)) {
						//获取对应的BeanDefinition
						BeanDefinition bd = registry.getBeanDefinition(candidateName);
						//检查BeanDefinition 拥有@Configuration注解 ,并且在处理过的装配类缓存中不存在
						if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
								!alreadyParsedClasses.contains(bd.getBeanClassName())) {
							//追加到candidates缓存,下一次循环会继续处理	
							candidates.add(new BeanDefinitionHolder(bd, candidateName));
						}
					}
				}
				candidateNames = newCandidateNames;
			}
		}
		while (!candidates.isEmpty());

		//往IOC容器注册 自动装配类队列,队列里面包含了符合条件的自动装配类,名称为ConfigurationClassPostProcessor.importRegistry 
		if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
			sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
		}

		if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
			// Clear cache in externally provided MetadataReaderFactory; this is a no-op
			// for a shared cache since it'll be cleared by the ApplicationContext.
			((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
		}
	}

从IOC容器遍历所有注册的 BeanDefinition ,并对目标Class的注解进行递归查找拥有@Configuration注解的 BeanDefinition,
第一次加载会加载到启动类对应的BeanDefinition ,我们查看 @SpringBootApplication 源码
会看到@SpringBootConfiguration ,点击查看 @SpringBootConfiguration会看到 @Configuration,此时有些读者会有疑问,在哪里把启动类注册到
IOC容器中,我在这里就不再往前翻源码了,在org.springframework.boot.SpringApplication.prepareContext中注册的,有兴趣的读者可以去看看
重点来了,此时我们把 启动类对应的BeanDefinition 交给 ConfigurationClassParser.parse()进行处理,
在里面会得到所有的自动装配类集合,并把集合交给 ConfigurationClassBeanDefinitionReader.loadBeanDefinitions() 进行 BeanDefinition 注册处理。
我们把目光移到 ConfigurationClassParser.parse() 中继续跟踪源码,查看是如何获取自动装配类

public void parse(Set<BeanDefinitionHolder> configCandidates) {
		//初始化缓存集合
		this.deferredImportSelectors = new LinkedList<>();
		//遍历装配包装类
		for (BeanDefinitionHolder holder : configCandidates) {
			//得到真正装配类的 BeanDefinition
			BeanDefinition bd = holder.getBeanDefinition();
			try {
				//根据BeanDefinition 的不同实现类,委派给相应的解析方法
				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);
			}
		}
		//最后处理DeferredImportSelector的实现类
		processDeferredImportSelectors();
}

我们重点关注三个不同的parse()解析方法,可以看到最终是委派给
processConfigurationClass (ConfigurationClass configClass) 进行处理

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
		//检查装配类是否需要跳过装配
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}
		//检查缓存是否加载过此装配类
		ConfigurationClass existingClass = this.configurationClasses.get(configClass);
		if (existingClass != null) {
			//如果装配类已加载
			if (configClass.isImported()) {
				//如果缓存装配类已加载
				if (existingClass.isImported()) {
					//合并加载类是由哪个装配类带出来的,可以理解为合并装配类的leader
					existingClass.mergeImportedBy(configClass);
				}
				// Otherwise ignore new imported config class; existing non-imported class overrides it.
				return;
			}
			else {
				//从缓存中删除装配类
				this.configurationClasses.remove(configClass);
				this.knownSuperclasses.values().removeIf(configClass::equals);
			}
		}

		// 将装配类转换为 SourceClass
		SourceClass sourceClass = asSourceClass(configClass);
		
		/**
				开始循环解析 ConfigurationClass 重点关注!
		**/
		do {
			sourceClass = doProcessConfigurationClass(configClass, sourceClass);
		}
		while (sourceClass != null);
		
		//缓存装配类
		this.configurationClasses.put(configClass, configClass);
}

这里主要做了3个事情
1、检查装配类是否需要跳过装配, 此处用于解析包含 @Conditional 注解的装配类,例如 @ConditionalOnClass @ConditionalOnBean @ConditionalOnProperty
2、检查是否重复加载,如果缓存里存在,则忽略
3、将装配类转换为 SourceClass , 并委派给 doProcessConfigurationClass() 进行解析,如果返回的结果不为空,则继续循环解析

我们先看SpringBoot是如何解析 @Conditional

public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
		//检查是否包含@Conditional注解
		if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
			return false;
		}
		
		//忽略此处,次数是在 phase 入参为空时,根据 metadata 是否包含@Configuration注解 为phase赋值
		if (phase == null) {
			if (metadata instanceof AnnotationMetadata &&
					ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
				return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
			}
			return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
		}

		//初始化 Condition 缓存 
		List<Condition> conditions = new ArrayList<>();
		//获取@Condition注解列表, 并获取value属性转换为列表
		for (String[] conditionClasses : getConditionClasses(metadata)) {
			for (String conditionClass : conditionClasses) {
				//实例化 Condition 实现类
				Condition condition = getCondition(conditionClass, this.context.getClassLoader());
				//追加缓存
				conditions.add(condition);
			}
		}
		
		//排序
		AnnotationAwareOrderComparator.sort(conditions);

		//遍历 Condition 缓存 
		for (Condition condition : conditions) {
			ConfigurationPhase requiredPhase = null;
			if (condition instanceof ConfigurationCondition) {
				requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
			}
			//调用condition.matches 如果返回false,则表示需要跳过
			if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
				return true;
			}
		}

		return false;
	}

上面主要获取装配类的所有 @Conditional 注解的 value 属性 ,并进行实例化,得到一组Condition 实现类, 最后进行遍历,依次调用 Condition.match() ,如果其中1个实现类返回false,则表示该装配类需要跳过 , 我们点击跟踪 SpringBootCondition 查看 match() 源码

public final boolean matches(ConditionContext context,
			AnnotatedTypeMetadata metadata) {
		//获取类名或者方法名
		String classOrMethodName = getClassOrMethodName(metadata);
		try {
			//获取是否匹配结果
			ConditionOutcome outcome = getMatchOutcome(context, metadata);
			//打印日志
			logOutcome(classOrMethodName, outcome);
			recordEvaluation(context, classOrMethodName, outcome);
			//返回是否匹配
			return outcome.isMatch();
		}
		catch (NoClassDefFoundError ex) {
			//忽略相关代码
		}
		catch (RuntimeException ex) {
			//忽略相关代码
		}
	}

getMatchOutcome() 是抽象方法 , 因为SpringBoot提供了很多 @ConditionOnXXX 注解 这些注解都对应一个实现类,实现了matches 方法,我们拿 @ConditionalOnClass 举例

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {

	
	Class<?>[] value() default {};

	/**
	 * The classes names that must be present.
	 * @return the class names that must be present.
	 */
	String[] name() default {};

}

可以看到 @Conditional 注解的值为 OnClassCondition , 我们进入 OnClassCondition 查看
getMatchOutcome 实现逻辑

public ConditionOutcome getMatchOutcome(ConditionContext context,
			AnnotatedTypeMetadata metadata) {
		ClassLoader classLoader = context.getClassLoader();
		ConditionMessage matchMessage = ConditionMessage.empty();
		//获取@ConditionalOnClass注解的value值并转换为String
		List<String> onClasses = getCandidates(metadata, ConditionalOnClass.class);
		//如果onClasses不为空
		if (onClasses != null) {
			//得到上下文中不存在的class集合
			List<String> missing = getMatches(onClasses, MatchType.MISSING, classLoader);
			//如果missing不为空, 证明依赖的Class不存在,返回ConditionOutcome.noMatch
			if (!missing.isEmpty()) {
				return ConditionOutcome
						.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
								.didNotFind("required class", "required classes")
								.items(Style.QUOTE, missing));
			}
			matchMessage = matchMessage.andCondition(ConditionalOnClass.class)
					.found("required class", "required classes").items(Style.QUOTE,
							getMatches(onClasses, MatchType.PRESENT, classLoader));
		}
		//获取 @ConditionalOnMissingClass 注解的value值并转换为String
		List<String> onMissingClasses = getCandidates(metadata,
				ConditionalOnMissingClass.class);
		if (onMissingClasses != null) {
			//得到上下文中存在的class集合
			List<String> present = getMatches(onMissingClasses, MatchType.PRESENT,
					classLoader);
			//如果 present 不为空, 证明需要不存在的Class反而存在,返回ConditionOutcome.noMatch
			if (!present.isEmpty()) {
				return ConditionOutcome.noMatch(
						ConditionMessage.forCondition(ConditionalOnMissingClass.class)
								.found("unwanted class", "unwanted classes")
								.items(Style.QUOTE, present));
			}
			matchMessage = matchMessage.andCondition(ConditionalOnMissingClass.class)
					.didNotFind("unwanted class", "unwanted classes").items(Style.QUOTE,
							getMatches(onMissingClasses, MatchType.MISSING, classLoader));
		}
		//走到这里,证明满足条件,返回 ConditionOutcome.match
		return ConditionOutcome.match(matchMessage);
	}

这里会获取装配类的 @ConditionalOnClass 的value值,并转换为 String , 从类加载器中查看
是否包含 onClasses ,如果其中一个不包含,则返回 ConditionOutcome.noMatch() 不匹配规则, 如果匹配继续往下走,
获取装配类的 @ConditionalOnMissingClass 的value值,并转换为 String , 从类加载器中查看是否不包含 **onMissingClasses ** 如果其中一个包含,则返回 ConditionOutcome.noMatch() 不匹配规则
这2个条件都满足则返回 ConditionOutcome.match() 匹配成功

我们回到 processConfigurationClass() 中, 继续追踪

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
		//检查装配类是否需要跳过装配
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}
		//检查缓存是否加载过此装配类
		ConfigurationClass existingClass = this.configurationClasses.get(configClass);
		if (existingClass != null) {
			//如果装配类已加载
			if (configClass.isImported()) {
				//如果缓存装配类已加载
				if (existingClass.isImported()) {
					//合并加载类是由哪个装配类带出来的,可以理解为合并装配类的leader
					existingClass.mergeImportedBy(configClass);
				}
				// Otherwise ignore new imported config class; existing non-imported class overrides it.
				return;
			}
			else {
				//从缓存中删除装配类
				this.configurationClasses.remove(configClass);
				this.knownSuperclasses.values().removeIf(configClass::equals);
			}
		}

		// 将装配类转换为 SourceClass
		SourceClass sourceClass = asSourceClass(configClass);
		
		/**
				开始循环解析sourceClass
			**/
		do {
			sourceClass = doProcessConfigurationClass(configClass, sourceClass);
		}
		while (sourceClass != null);
		
		//缓存装配类
		this.configurationClasses.put(configClass, configClass);
}

我们将目光移到,将装配类转换为 SourceClass , 并委派给 doProcessConfigurationClass() 进行解析,如果返回的结果不为空,则继续循环解析

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {

		//检查是否有Component注解, 如果拥有的话, 遍历其内部类拥有@Configuration注解的类,递归processConfigurationClass()解析
		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			processMemberClasses(configClass, sourceClass);
		}

		// 检查是否有 @PropertySource 注解 ,有的话则加载配置文件, 追加到环境变量 Environment 中
		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");
			}
		}

		// 获取 @ComponentScan 注解配置信息
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		//检查是否拥有 @ComponentScan 注解信息,并且满足加载条件 进入扫描代码块
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				/**
					委派给 ComponentScanAnnotationParser 把带有自动装配注解的类(例如:@Compoent @Service)扫描出来,并加载到IOC容器中,
					因为 @SpringBootApplication 注解中包含了 @ComponentScan 注解, 所以会扫描启动类所在包下的所有类
				**/
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// 遍历扫描出来的元数据 BeanDefinitionHolder
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					//检查扫描的类是否包含 @Configuration  ,包含则优先解析扫描出来的 ConfigurationClass 配置类
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		/**
			处理 @Import 注解, 主要逻辑是:
			1、遍历 @Import 的值
			2、判断值的所属类型
				2.1、如果是ImportSelector的实现类,则调用 selectImports() 返回 一组配置类递归给 processImports() 方法加载
				2.2、如果是 DeferredImportSelector 的实现类,则加载到 deferredImportSelectors 内存中 ,延迟加载
				2.3、如果是 ImportBeanDefinitionRegistrar 的实现类,则会追加到对应的 ConfigurationClass 的importBeanDefinitionRegistrars属性中
					 最后在ConfigurationClassParser.loadBeanDefinitions() 对所有ConfigurationClass进行加载时,
					 会调用 ImportBeanDefinitionRegistrar.registerBeanDefinitions() 通过编码的方式扩展,加载Bean元数据
				2.4、如果都不是,当成一个配置类, 递归processConfigurationClass() 加载解析
				
			
			我们重点关注 DeferredImportSelector , 因为 @EnableAutoConfiguration 注解里导入的类是 AutoConfigurationImportSelector 
		**/
		processImports(configClass, sourceClass, getImports(sourceClass), true);

		/**
			处理 @ImportResource 注解, 把spring的bean配置文件缓存到 ConfigurationClass.importedResources中,
			最后在ConfigurationClassParser.loadBeanDefinitions() 对所有ConfigurationClass进行加载时,会使用 XmlBeanDefinitionReader 进行解析加载
			
		**/
		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);
			}
		}

		// 处理 带有 @Bean 注解修饰的方法, 并缓存到  ConfigurationClass.beanMethods 
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// 没太明白做的逻辑, 以后再说
		processInterfaces(configClass, sourceClass);

		// 查看是否拥有父类, 并且父类不是java开头的包, 则返回父类,循环加载父类配置信息
		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();
			}
		}

		// 没有父类, 外层循环结束
		return null;
	}

我们把目光移到 ConfigurationClassParser.parse() 代码块里的
processDeferredImportSelectors();
中继续跟踪源码,查看是如何获取要自动装配的配置类

public void process() {
	List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
	this.deferredImportSelectors = null;
	try {
		if (deferredImports != null) {
			//构造 DeferredImportSelectorGroupingHandler 
			DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
			//对deferredImports进行排序
			deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
			
			/**
				遍历 deferredImports 并依次调用handler.register(DeferredImportSelectorHolder holder)
				在里面主要获取DeferredImportSelector.getImportGroup() 类型, 实例化后 保存到DeferredImportSelectorGroupingHandler.groupings属性中
			**/
			deferredImports.forEach(handler::register);
			/**
				依次调用
				DeferredImportSelector.Group.process()     在这里面会去加载spring.factories配置文件中key=EnableAutoConfiguration的配置项,
				并封装成一组配置集合,并对其进行过滤, 过滤掉一些不符合加载条件的配置类
				
				DeferredImportSelector.Group.selectImports()  会对配置集合进行排序, 根据这几个注解进行排序 :
				@Order @AutoConfigureBefore @AutoConfigureAfter
				
			**/
			handler.processGroupImports();
		}
	}
	finally {
		this.deferredImportSelectors = new ArrayList<>();
	}
}

解析handler.processGroupImports

public void processGroupImports() {
			//遍历注册在缓存中的DeferredImportSelector的包装类
			for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
				//grouping.getImports() 主要是加载spring.factories的自动装配类,并对其过滤 排序
				grouping.getImports().forEach(entry -> {
					ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
					try {
						//正式开始加载自动装配类 我们比较熟悉的RedisAutoConfiguration RabbitAutoConfiguration就是在这里进行装配的
						processImports(configurationClass, asSourceClass(configurationClass),
								asSourceClasses(entry.getImportClassName()), false);
					}
					catch (BeanDefinitionStoreException ex) {
						throw ex;
					}
					catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to process import candidates for configuration class [" +
										configurationClass.getMetadata().getClassName() + "]", ex);
					}
				});
			}
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值