likes
comments
collection
share

Spring Boot实现自动配置源码解析

作者站长头像
站长
· 阅读数 32

概述

自动配置为Spring Boot的一大特性,根据引入的Jar包情况,动态的生成一组Bean,接下来我们从源码层面看下Spring Boot是如何实现自动配置的。

@EnableAutoConfiguration

所有的Spring Boot项目都必定有一个@SpringBootApplication注解,自动配置的入口也是该注解。

@SpringBootApplication注解是一个组合注解:

// SpringBootApplication.java

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

本篇文章我们只关心自动配置,所以仅关注@EnableAutoConfiguration注解即可。

我们再看下@EnableAutoConfiguration注解。 org.springframework.boot.autoconfigure.@EnableAutoConfiguration 注解,用于开启自动配置功能

// EnableAutoConfiguration.java

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
	Class<?>[] exclude() default {};

	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};

}
  • @Import(AutoConfigurationImportSelector.class)
    • org.springframework.context.annotation.@Import 注解:用于资源的导入
    • AutoConfigurationImportSelector导入自动配置相关的资源。这是本文的重点。

AutoConfigurationImportSelector

org.springframework.boot.autoconfigure.AutoConfigurationImportSelector ,实现 DeferredImportSelectorBeanClassLoaderAwareResourceLoaderAwareBeanFactoryAwareEnvironmentAwareOrdered 接口,处理 @EnableAutoConfiguration 注解的资源导入。

先看下自动配置类的基本加载过程,调用栈如下图所示: Spring Boot实现自动配置源码解析

  1. ApplicationContext#refresh作为入口开始加载自动配置类
  2. 仍然是Spring框架部分,提供了一种可扩展的导入配置类方式
  3. AutoConfigurationImportSelector.AutoConfigurationGroup#process作为Spring Boot的具体实现,加载META-INFO/spring.factories下声明的EnableAutoConfiguration自动配置类

Spring Boot从自动配置类加载BeanDefinition的完整流程如下:

Spring Boot实现自动配置源码解析

既然,用户自定义的BeanDefinition在自动配置类加载之前已经进入BeanFactory,为什么不在AutoConfigurationImportSelector#filter阶段,既过滤自动配置类,又加载对应的BeanDefinition?而是在ConfigurationClassParser.DeferredImportSelectorGroupingHandler#processGroupImports阶段做?

ConfigurationClassPostProcessor

// ConfigurationClassPostProcessor
	public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
        ......

        //存放所有的BeanDefinitionHolder
		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {
            //(\*\*)ConfigurationClassParser解析configCandidates中的配置类
            //如果有@ComponentScan注解,扫描指定配置的所有配置类
            //注册@Configuration类的BeanDefinition到BeanDefinitionRegistry
            //1 ConfigurationClassParser.configurationClasses保存了所有的ConfigurationClass
			parser.parse(candidates);
            //校验ConfigurationClass的有效性
			parser.validate();

            //获取解析后的配置类
			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
            //移除已经解析的类
			configClasses.removeAll(alreadyParsed);

			// 通过ConfigurationClassBeanDefinitionReader加载BeanDefinition到BeanDefinitionRegistry
			if (this.reader == null) {
				this.reader = new ConfigurationClassBeanDefinitionReader(
						registry, this.sourceExtractor, this.resourceLoader, this.environment,
						this.importBeanNameGenerator, parser.getImportRegistry());
			}
            // <2> (\*\*)扫描configClasses的所有配置类,@Bean方法为BeanDefinition,
            // 条件注解@Conditional的判断也在这里生效
			this.reader.loadBeanDefinitions(configClasses);
            
    
    ......
}
  • 1 处
    • 加载用户自定义BeanDefinition
    • 加载Spring Boot自动配置类的入口,根据条件加载自动配置类
  • 2处: 处理@Confiuration配置类,包括自动配置类,

Spring Boot实现自动配置源码解析

  • 执行完ConfigurationClassParser#parse即会加载Spring Boot的自动配置类,也会加载用户自定义的配置类。

ConfigurationClassParser

ConfigurationClassParser#doProcessConfigurationClass:执行真正的配置类处理逻辑。根据当前配置类的注解,加载其它的BeanDefinition。如:@Component@PropertySources@ComponentScans@ImportResource

#parse

// ConfigurationClassParser

	public void parse(Set<BeanDefinitionHolder> configCandidates) {
		// 从SpringApplication类加载Bean定义
        for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
                // 1.加载SpringApplication扫描各种资源,包括@ComponentScan、@Import、@PropertySources、@Component等,可见`ConfigurationClassParser#doProcessConfigurationClass`
                //(\*\*)用户自定义的配置类是在这里注册为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);
			}
		}

        // 2.执行自动配置类的处理过程
		this.deferredImportSelectorHandler.process();
	}
  1. 很关键的点,用户自定义的BeanDefinition是在该处加载到BeanFactory,如@Component@Configuration
  2. 开始加载Spring Boot的自动配置类

(**)#processGroupImports

  • ConfigurationClassParser.DeferredImportSelectorGrouping#getImports:获取自动配置类,并做初次过滤,因为此时并没有用到BeanFactory,仅是根据过滤条件过滤一部分自动配置类
  • ConfigurationClassParser#processImports:
    1. 根据@Conditional注解结合BeanFactory做二次过滤
    2. 处理配置类,
// ConfigurationClassParser

	private class DeferredImportSelectorGroupingHandler {
.....
		public void processGroupImports() {
			for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
				grouping
                    // 1.导入自动配置类
                    .getImports()
                    .forEach(entry -> {
					ConfigurationClass configurationClass = this.configurationClasses.get(
							entry.getMetadata());
					try {
                        // 2.处理自动配置类,
                        // @Conditional注解的二次过滤
                        // 根据配置类的注解加载BeanDefinition,如:`@Component`、`@PropertySources`、`@ComponentScans`、`@ImportResource`
						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);
					}
				});
			}
		}
        ......
            
  • 1处:会导入自动配置类,并做初次过滤,过滤的入口为FilteringSpringBootCondition#match
  • 2处:处理自动配置类
    1. 对自动配置类做二次过滤,过滤的入口为SpringBootCondition#match
    2. 通过自动配置类加载资源

#getImports

// ConfigurationClassParser.DeferredImportSelectorGrouping
		// 导入自动配置类
		public Iterable<Group.Entry> getImports() {
            //遍历DeferredImportSelectorHolder
			for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
                //导入自动配置类,并做初次过滤
				this.group.process(deferredImport.getConfigurationClass().getMetadata(),
						deferredImport.getImportSelector());
			}
            //返回当前Group的List<Entry>,实际上就是最终的导入的自动配置类
			return this.group.selectImports();
		}
  • group#process:导入自动配置类,并做初次过滤。Spring Boot项目中的groupAutoConfigurationSelector.AutoConfigurationGroup,即调用了AutoConfigurationGroup#process,加载符合条件的自动配置类(META-INFO/spring.factories中指定的org.springframework.boot.autoconfigure.EnableAutoConfiguration类)。
  • group#selectImports:排除无需导入的配置类,做排序,导入配置类

Spring Boot实现自动配置源码解析

AutoConfigurationSelector.AutoConfigurationGroup

(**)AutoConfigurationGroup#process

获取符合条件的自动配置类。

private static class AutoConfigurationGroup implements DeferredImportSelector.Group,
			BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
		
        //   AnnotationMetadata annotationMetadata:如@SpringBootApplication注解      
        @Override
		public void process(AnnotationMetadata annotationMetadata,
				DeferredImportSelector deferredImportSelector) {
			//.....
			//(\*\*)调用AutoConfigurationImportSelector获取AutoConfigurationEntry,主要包含符合条件的自动配置类
			AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
					.getAutoConfigurationEntry(getAutoConfigurationMetadata(),
							annotationMetadata);
			//添加到autoConfigurationEntries
			this.autoConfigurationEntries.add(autoConfigurationEntry);
			//对每一个符合条件的配置类名称和注解信息保存到Map中
			for (String importClassName : autoConfigurationEntry.getConfigurations()) {
				this.entries.putIfAbsent(importClassName, annotationMetadata);
			}
		}


        .......
 }

#selectImports

// AutoConfigurationGroup
		@Override
		public Iterable<Entry> selectImports() {
			if (this.autoConfigurationEntries.isEmpty()) {
				return Collections.emptyList();
			}
			//得到所有要排除的自动配置类
			Set<String> allExclusions = this.autoConfigurationEntries.stream()
					.map(AutoConfigurationEntry::getExclusions)
					.flatMap(Collection::stream).collect(Collectors.toSet());
			//得到所有符合条件的自动配置类
			Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
					.map(AutoConfigurationEntry::getConfigurations)
					.flatMap(Collection::stream)
					.collect(Collectors.toCollection(LinkedHashSet::new));
			//移除需要排除的配置类
			processedConfigurations.removeAll(allExclusions);

			// 对标注有@Order自动配置类做排序
			// 封装成List<Entry>,返回
            // 1. @AutoConfigureOrder、@AutoConfigureBefore、@AutoConfigureAfter都在这里生效
			return sortAutoConfigurations(processedConfigurations,
					getAutoConfigurationMetadata())
							.stream()
							.map((importClassName) -> new Entry(
									this.entries.get(importClassName), importClassName))
							.collect(Collectors.toList());
		}	
  • 1处:对自动配置类做排序,可见@AutoConfigureOrder@AutoConfigureBefore@AutoConfigureAfter,仅对自动配置类生效,也就是说,必须声明在META-INFO/spring.factories中指定的org.springframework.boot.autoconfigure.EnableAutoConfiguration

(**)AutoConfigurationImportSelector —— 自动过滤的主体逻辑

封装了自动导入配置类的核心逻辑。

public class AutoConfigurationImportSelector
		implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
		BeanFactoryAware, EnvironmentAware, Ordered {
    //......
            
    /**
     *	核心逻辑
     */
	protected AutoConfigurationEntry getAutoConfigurationEntry(
			AutoConfigurationMetadata autoConfigurationMetadata,
			AnnotationMetadata annotationMetadata) {
		//是否启用自动配置
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		//1. 获取所有的候选自动配置类
		List<String> configurations = getCandidateConfigurations(annotationMetadata,
				attributes);
		//2.去除重复的自动配置类(通过Set实现)
		configurations = removeDuplicates(configurations);
		//从注解信息中获取排除的配置类
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		//排除exclude的配置类
		configurations.removeAll(exclusions);
		//3.(\*\*) 使用spring.factories中指定的AutoConfigurationImportFilter对自动配置类(configurations)过滤,这里实现类是FilteringSpringBootCondition
		configurations = filter(configurations, autoConfigurationMetadata);
		//4.调用`AutoConfigurationImportListener`发布自动配置类导入事件
		fireAutoConfigurationImportEvents(configurations, exclusions);
		//用AutoConfigurationEntry封装匹配的配置类和需要排除的配置类
		return new AutoConfigurationEntry(configurations, exclusions);
	}
    
    
}
  1. 加载所有的配置类
  2. 去除重复,去除exclusions中的配置类
  3. filter()过滤自动配置类,调用的spring.factories中指定的AutoConfigurationImportFilter,过滤配置类
  4. 触发自动配置导入事件

getCandidateConfigurations —— 获取全部自动配置类

#getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) 方法,加载在 META-INF/spring.factories 指定的全部 EnableAutoConfiguration数组。代码如下:

// AutoConfigurationImportSelector.java

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    // 1. 加载在 `META-INF/spring.factories` 指定的全部 `EnableAutoConfiguration` 
	List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
        getSpringFactoriesLoaderFactoryClass(), //EnableAutoConfiguration.class
        getBeanClassLoader());
	// 断言非空
	Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct.");
	return configurations;
}
  • 1 处,调用 #getSpringFactoriesLoaderFactoryClass() 方法,返回指定类型为 EnableAutoConfiguration 类。代码如下:

    // AutoConfigurationImportSelector.java
    
    protected Class<?> getSpringFactoriesLoaderFactoryClass() {
    	return EnableAutoConfiguration.class;
    }
    
  • 1处,调用 SpringFactoriesLoader#loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) 方法,加载 META-INF/spring.factories 指定类型为 EnableAutoConfiguration全部自动配置类

Spring Boot实现自动配置源码解析

(**)filter —— 过滤自动配置类

这一层过滤并不是完整的过滤。如:在该阶段BeanFactory中并BeanDefinition,OnBeanCondition在该阶段无法判断BeanDefinition是否存在,仅判断对应的Bean的Class是否存在

// AutoConfigurationImportSelector
	
	private List<String> filter(List<String> configurations,
			AutoConfigurationMetadata autoConfigurationMetadata) {
		long startTime = System.nanoTime();
		//所有的配置类
		String[] candidates = StringUtils.toStringArray(configurations);
		//初始化skip数组,默认为false
		boolean[] skip = new boolean[candidates.length];
		boolean skipped = false;
		// 获取META-INFO/spring.factories文件中,指定的`AutoConfigurationImportFilter`类数组
        // 1. 基本的Spring Boot项目包括:OnClassCondition、OnWebApplicationCondition、OnBeanCondition
		for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
			invokeAwareMethods(filter);
			//2. AutoConfigurationImportFilter对所有的配置类匹配,得到匹配结果
			boolean[] match = filter.match(candidates, autoConfigurationMetadata);
			for (int i = 0; i < match.length; i++) {
				//如果不匹配
				if (!match[i]) {
					//对应的skip设置为true
					skip[i] = true;
					//3. (\*\*)candidates数组中对应设置为空,即该自动配置类,无需参与下一轮的AutoConfigurationImportFilter#match
					candidates[i] = null;
					skipped = true;
				}
			}
		}
		//只要有一个不匹配,skipped就会为true,就不会直接返回所有的配置类
		if (!skipped) {
			return configurations;
		}
		List<String> result = new ArrayList<>(candidates.length);
		for (int i = 0; i < candidates.length; i++) {
			// skip==false,就添加到结果集里
			if (!skip[i]) {
				result.add(candidates[i]);
			}
		}
		if (logger.isTraceEnabled()) {
			int numberFiltered = configurations.size() - result.size();
			logger.trace("Filtered " + numberFiltered + " auto configuration class in "
					+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)
					+ " ms");
		}
		//返回需要加载的自动配置类结果集
		return new ArrayList<>(result);
	}
  • 1处:说明Spring Boot内置支持的自动配置类由OnClassConditionOnWebApplicationConditionOnBeanCondition三个AutoConfigurationImportFilter的实现类支持
    • Spring Boot实现自动配置源码解析
  • 2处:调用AutoConfigurationImportFilter#match匹配结果
  • 3处:只要自动配置类有一个AutoConfigurationImportFilter#match的结果不匹配,就会直接被剔除,不会进入下一轮AutoConfigurationImportFilter#match

AutoConfigurationImportFilter ——自动配置类导入过滤器

AutoConfigurationImportFilter注释:

"fast removal of auto-configuration classes before their bytecode is even read":做初次过滤,因为自动配置类可能会很多,如果无需使用,就没有必要加载自定的自动配置类。

org.springframework.boot.autoconfigure.AutoConfigurationImportFilter 接口,用于过滤掉无需自动引入的自动配置类。

类图如下:

Spring Boot实现自动配置源码解析

  • AutoConfigurationImportFilter:实现了AutoConfigurationImportFilter的抽象基类
  • OnBeanConditionOnWebApplicationConditionOnClassCondition都是AutoConfigurationImportFilter的实现类
@FunctionalInterface
public interface AutoConfigurationImportFilter {

	/**
	 * 过滤自动配置类
	 * @param autoConfigurationClasses 待过滤的自动配置类列表
	 * @param autoConfigurationMetadata 元数据信息
	 * @return 一个boolean数组,表示哪些自动配置类是匹配的
	 */
	boolean[] match(String[] autoConfigurationClasses,
			AutoConfigurationMetadata autoConfigurationMetadata);

}
  • 将传入的 autoConfigurationClasses 配置类们,根据 autoConfigurationMetadata 的元数据(主要是注解信息),进行匹配,判断是否需要引入,然后返回的 boolean[] 结果。
  • 并且,boolean[] 结果和 autoConfigurationClasses 配置类们是一一对应的关系。假设 autoConfigurationClasses[0] 对应的 boolean[0]false ,表示无需引入,反之则需要引入。

FilteringSpringBootCondition

org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition ,继承 SpringBootCondition 抽象类,实现 AutoConfigurationImportFilterBeanFactoryAwareBeanClassLoaderAware 接口。

  1. 具备SpringBootConditionboolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)过滤一般的@Conditional修饰的@Configuration配置类。在初次过滤的过程中,是不会涉及SpringBootCondition#matches方法的。
  2. 具备AutoConfigurationImportFilterboolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata)批量过滤META-INFO/spring.factories指定的自动配置类

FilteringSpringBootCondition的实现类有:

  • OnWebApplicationCondition
  • OnClassCondition
  • OnBeanCondition

#match

abstract class FilteringSpringBootCondition extends SpringBootCondition
		implements AutoConfigurationImportFilter, BeanFactoryAware, BeanClassLoaderAware {
    // 仅仅是将`ConditionOutcome[] outcomes` -> `boolean[] match`,做一些记录
    // 具体的逻辑由#getOutcomes实现
	@Override
	public boolean[] match(String[] autoConfigurationClasses,
			AutoConfigurationMetadata autoConfigurationMetadata) {
		ConditionEvaluationReport report = ConditionEvaluationReport
				.find(this.beanFactory);
		//getOutcomes()是抽象方法,由子类实现
		//对于每一个配置类都执行对应的getOutcomes()匹配,得到匹配结果,记录到ConditionOutcome数组中
		ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses,
				autoConfigurationMetadata);
		//记录匹配结果
		boolean[] match = new boolean[outcomes.length];
		for (int i = 0; i < outcomes.length; i++) {
            //匹配成功的条件:outcomes[i]== null或者outcomes[i].isMatch==true
			match[i] = (outcomes[i] == null || outcomes[i].isMatch());
			//匹配不成功,则记录日志
			if (!match[i] && outcomes[i] != null) {
				logOutcome(autoConfigurationClasses[i], outcomes[i]);
				if (report != null) {
					report.recordConditionEvaluation(autoConfigurationClasses[i], this,
							outcomes[i]);
				}
			}
		}
		return match;
	}
    
    // 由子类实现具体的匹配逻辑
    protected abstract ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
			AutoConfigurationMetadata autoConfigurationMetadata);
}

FilteringSpringBootCondition#ClassNameFilter

ClassNameFilter是FilteringSpringBootCondition的内部枚举,用于判断类加载器是否能加载指定的类名

// FilteringSpringBootCondition
	protected enum ClassNameFilter {
		// 如果类加载器加载类成功,即匹配
		PRESENT {

			@Override
			public boolean matches(String className, ClassLoader classLoader) {
				return isPresent(className, classLoader);
			}

		},

        // 如果类加载器加载类失败,即匹配
		MISSING {

			@Override
			public boolean matches(String className, ClassLoader classLoader) {
				return !isPresent(className, classLoader);
			}

		};

		abstract boolean matches(String className, ClassLoader classLoader);

		static boolean isPresent(String className, ClassLoader classLoader) {
            // 设置默认类加载器
			if (classLoader == null) {
				classLoader = ClassUtils.getDefaultClassLoader();
			}
			try {
                // 尝试加载类,加载成功返回true
				resolve(className, classLoader);
				return true;
			}
			catch (Throwable ex) {
				return false;
			}
		}

	}
  • 从这里可以看到OnBeanCondition在匹配自动配置类时,仅加载类,并没有通过BeanDefinition判断Bean是否存在BeanFactory中

OnBeanCondition

可用于调试的配置类

  • org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration
  • org.springframework.boot.autoconfigure.http.JacksonHttpMessageConvertersConfiguration.MappingJackson2HttpMessageConverterConfiguration

OnBeanCondition#getOutcomes

// OnBeanCondition
	// 由FilteringSpringBootCondition的match进入

	// autoConfigurationClasses:这里一些配置类在前几轮未能匹配成功,已经被设置为null
	@Override
	protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
			AutoConfigurationMetadata autoConfigurationMetadata) {
		//用于保存每个Condition的匹配结果
		ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
		for (int i = 0; i < outcomes.length; i++) {
			String autoConfigurationClass = autoConfigurationClasses[i];
			if (autoConfigurationClass != null) {
				//获取@ConditionalOnBean指定的Class[]
				Set<String> onBeanTypes = autoConfigurationMetadata
						.getSet(autoConfigurationClass, "ConditionalOnBean");
				//匹配Bean是否存在
				outcomes[i] = getOutcome(onBeanTypes, ConditionalOnBean.class);
				//outcomes[i]==null表示匹配成功,进行@ConditionalOnSingleCandidate注解的匹配
				if (outcomes[i] == null) {
					//获取@ConditionalOnSingleCandidate指定的Class[]
					Set<String> onSingleCandidateTypes = autoConfigurationMetadata.getSet(
							autoConfigurationClass, "ConditionalOnSingleCandidate");
					outcomes[i] = getOutcome(onSingleCandidateTypes,
							ConditionalOnSingleCandidate.class);
				}
			}
		}
		return outcomes;
	}

OnBeanCondition#getOutcome

// OnBeanCondition
	private ConditionOutcome getOutcome(Set<String> requiredBeanTypes, Class<? extends Annotation> annotation) {
        // 获取类加载器加载失败的类名称    
		List<String> missing = filter(requiredBeanTypes, ClassNameFilter.MISSING, getBeanClassLoader());
		if (!missing.isEmpty()) {
            // 生成匹配失败的消息
			ConditionMessage message = ConditionMessage.forCondition(annotation)
					.didNotFind("required type", "required types").items(Style.QUOTE, missing);
            // 返回匹配失败的结果
			return ConditionOutcome.noMatch(message);
		}
        // 返回null,即匹配成功了
		return null;
	}

FilteringSpringBootCondition#filter

//FilteringSpringBootCondition
	protected final List<String> filter(Collection<String> classNames, ClassNameFilter classNameFilter,
			ClassLoader classLoader) {
        // 类名称列表为空,直接返回空列表
		if (CollectionUtils.isEmpty(classNames)) {
			return Collections.emptyList();
		}
		List<String> matches = new ArrayList<>(classNames.size());
        // 遍历类名称列表,用ClassNameFilter#match匹配,匹配的添加到matches数组
		for (String candidate : classNames) {
			if (classNameFilter.matches(candidate, classLoader)) {
				matches.add(candidate);
			}
		}
		return matches;
	}

OnBeanCondition为什么仅做类是否存在的判断?

  • 为什么OnBeanCondition都没有对BeanDefinition做判断,而是直接类是否存在做判断?
    • 在该阶段判断@ConditionalOnBean指定的Bean的类型是否存在,来过滤配置类,目的是减少加载进内存自动配置类的数量。
    • 之后,处理自动配置类,会再次进入OnBeanCondition#getMatchOutcome过滤

其它Condition

OnWebApplicationConditionOnClassCondition就不介绍了,感兴趣的朋友可以打断点调试一下,入口都是FilteringSpringBootCondition#match方法

转载自:https://juejin.cn/post/7271576714693148687
评论
请登录