SpringBoot源码解析三部曲(一)——自动配置

关联文章:
SpringBoot源码解析三部曲(二)——SpringApplication实例化
SpringBoot源码解析三部曲(三)——运行流程

1、Spring Boot项目结构

1.1 整体项目结构

以2.2.6.RELEASE为例:
Spring Boot整体项目结构
由图中可以看出,2.2.x.RELEASE版本由两个子模块构成:

  • spring-boot-project:Spring Boot核心项目代码,包含核心、工具、安全、文档、starters等项目
  • spring-boot-tests:Spring Boot部署及集成的测试

1.2 spring-boot-project项目结构

项目结构详情
重点模块解析:

  • spring-boot:Spring Boot核心代码,也是入口类SpringApplication类所在项目。
  • spring-boot-autoconfigure:Spring Boot自动配置核心功能,默认集成了多种常见框架的自动配置类等。
  • spring-boot-dependencies:依赖和插件的版本信息。
  • spring-boot-devtools:开发者工具,提供热部署、实时加载、禁用缓存等提升开发效率的功能。
  • spring-boot-starters:Spring Boot以预定义的方式集成了其他应用的starter集合。
  • spring-boot-test:测试功能相关代码。

2、Spring Boot自动配置运行原理

2.1、自动配置运行原理简介

Spring Boot自动配置运行原理如下图所示:
自动配置运行原理
可以用一句话来描述整个过程:Spring Boot通过@EnableAutoConfiguration注解开启自动配置,加载spring.factories中注册的各种AutoConfiguration类,当某个AutoConfiguration类满足其注解@Conditional指定的生效条件(Starters提供的依赖、配置或Spring容器中是否存在某个Bean等)时,实例化该AutoConfiguration类中定义的Bean,并注入Spring容器,就可以完成依赖框架的自动配置。
简单介绍一下图中所示的组件:

@EnableAutoConfiguration:该注解有组合注解@SpringBootApplication引入,完成自动配置开启,扫描各个jar包下的spring.factories文件,并加载文件中注册的AutoConfiguration类等。
spring.factories:配置文件,位与jar包的META-INF目录下,按照指定格式注册了自动配置的AutoConfiguration类。spring.factories也可以包含其他类型待注册的类。该配置文件不仅存在于Spring Boot项目中,也可以存在于自定义的自动配置(或Starter)项目中。
AutoConfiguration类:自动配置类,代表了Spring Boot中一类以XXAutoConfiguration命名的自动配置类。其中定义了三方组件集成Spring所需初始化的Bean和条件。
@Conditional:条件注解及其衍生注解,在AutoConfiguration类上使用,当满足该条件注解时才会实例化AutoConfiguration类。
Starters:三方组件的依赖及配置,Spring Boot已经预置的组件。Spring Boot默认的Starters项目往往只包含一个pom依赖的项目。如果是自定义的starter,该项目还需包含spring.factories文件、AutoConfiguration类和其他配置类。

2.2、自动配置源码解析之@EnableAutoConfiguration

@EnableAutoConfiguration是开启自动配置的注解,它是由@SpringBootApplication引入的。

2.2.1、入口类和@SpringBootApplication注解

Spring Boot项目会生成一个 xxxApplication的入口类,如下所示:

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

该类的main方法用于启动Spring Boot项目的入口。唯一的注解@SpringBootApplication,用于开启自动配置,准确地说是通过该注解内的@EnableAutoApplication开启了自动配置。

@SpringBootApplication源码如下:

@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 {

	// 排除指定自动配置类
	@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {};

	// 排除指定自动配置类名
	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};

	// 指定扫描的基础包,激活注解组件的初始化
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};

	// 指定扫描的类,用于初始化
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {};

	// 指定是否代理@Bean方法以强制执行bean的生命周期行为
	@AliasFor(annotation = Configuration.class)
	boolean proxyBeanMethods() default true;

}

该注解组合了@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan。@SpringBootConfiguration继承自@Configuration,用于标注当前类是配置类,将当前类中声明的一个或多个以@Bean注解标记的方法的实例装配到Spring容器中。@ComponentScan用于根据定义的扫描路径,把符合扫描规则的类装配到Spring容器中。

该注解提供了一下成员属性:
exclude:根据类(Class)排除指定的自动配置,该成员属性覆盖了@SpringBootApplication中组合的@EnableAutoConfiguration中定义的exclude成员属性。
excludeName:根据类名排除指定的自动配置,覆盖了@EnableAutoConfiguration中的excludeName的成员属性。
scanBasePackages:指定扫描的基础package,用于激活@Component等注解类的初始化。
scanBasePackageClasses:扫描指定的类,用于组件的初始化。
proxyBeanMethods:指定是否代理@Bean方法以强制执行bean的生命周期行为。此功能需要通过运行时生成CGLIB子类来实现方法拦截。

该注解中还大量使用@AliasFor注解,该注解用于桥接到其他注解,该注解的属性指定了所桥接的注解类。这些属性在其他注解中已经定义过了,之所以使用@AliasFor注解并重新在@SpringBootApplication中定义,更多是为了减少用户使用多注解带来的麻烦。

2.2.2、@EnableAutoConfiguration注解解析

未使用Spring Boot的情况下,Bean的生命周期由Spring来管理,然而Spring无法自动配置@Configuration注解的类,Spring Boot的核心功能之一就是根据约定自动管理该注解标注的类。@EnableAutoConfiguration的主要功能是启动Spring应用程序上下文时进行自动配置,它会尝试猜测并配置项目可能需要的Bean。自动配置通常是基于项目classpath中引入的类和已定义的Bean来实现的。

@EnableAutoConfiguration注解源码如下:

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

  	// 用于覆盖配置开启或关闭自动配置的功能
	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	// 根据类(Class)排除指定的自动配置
	Class<?>[] exclude() default {};

	// 根据类名排除指定的自动配置
	String[] excludeName() default {};

}

@EnableAutoConfiguration会猜测需要使用的Bean,但如果在项目中并不需要它预置初始化的Bean,可通过该注解的exclude或excludeName参数进行有针对性的排除。比如当不需要数据库自动配置时,可通过以下方式排除:

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class SpringBootDemoApplication {
}

2.3、AutoConfigurationImportSelector解析

@EnableAutoConfiguration的关键功能是通过@Import注解导入的ImportSelector接口来完成的,@Import(AutoConfigurationImportSelector.class)是自动配置功能的核心实现。

2.3.1、@Import注解解析

@Import注解主要提供导入配置类的功能,通过@Import可以引入@Configuration注解的类,也可以导入实现了ImportSelector接口或ImportBeanDefinitionRegistrar的类。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
    Class<?>[] value();
}

2.3.2、ImportSelector接口解析

@Import的功能基本都需要借助ImportSelector接口来实现,ImportSelector接口决定可引入哪些@Configuration。ImportSelector是Spring中的接口,源码如下:

public interface ImportSelector {
    String[] selectImports(AnnotationMetadata var1);

    @Nullable
    default Predicate<String> getExclusionFilter() {
        return null;
    }
}

ImportSelector接口只提供了一个参数为AnnotationMetadata的方法,返回的结果为一个字符串数组。其中参数AnnotationMetadata内包含了被@Import注解的类的注解信息。在selectImports方法内可根据具体实现决定返回哪些配置类的全限定名,将结果以字符串数组的形式返回。

AutoConfigurationImportSelector部分源码如下:

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    }

AutoConfigurationImportSelector并没有直接实现了ImportSelector接口,而是实现了它的子接口DeferredImportSelector,DeferredImportSelector会在所有的@Configuration类加载完成之后再加载返回的配置类,而ImportSelector是在加载完@Configuration类之前先去加载返回的配置类。
AutoConfigurationImportSelector还实现了BeanClassLoaderAware、ResourceLoaderAware、BeanFactoryAware、EnvironmentAware,Spring会保证在调用ImportSelector之前会先调用Aware接口的方法。

2.3.3、AutoConfigurationImportSelector功能概述

AutoConfigurationImportSelector的核心功能和流程图如下:
在这里插入图片描述当AutoConfigurationImportSelector被@Import注解引入之后,它的selectImports方法会被调用并执行其实现的自动装配逻辑。读者朋友需注意,selectImports方法几乎涵盖了组件自动装配的所有处理逻辑。源码如下:

	/**
   	 * AnnotationMetadata包含了被@Import注解的类的注解信息
   	 * 返回值为配置类的全限定名字符串数组
   	 */
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
    	// 检查自动配置功能是否开启,默认为开启
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
    	// 加载自动配置的元信息,配置文件为类路径中META-INF目录下的spring-autoconfigure-metadata.properties文件
		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
				.loadMetadata(this.beanClassLoader);
    	// 封装将被引入的自动配置信息
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
				annotationMetadata);
    	// 返回符合条件的配置类的全限定名数组
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

3、AutoConfigurationImportSelector代码分析详解

3.1、isEnabled方法

该方法用来检查自动配置功能是否开启,默认为开启状态

/**
 * 判断是否开启自动配置功能
 */
protected boolean isEnabled(AnnotationMetadata metadata) {
		/**
		 * 如果当前类为AutoConfigurationImportSelector, 程序会从环境中获取key为EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY的配置,
		 * 该常量的值为spring.boot.enableautoconfiguration. 如果获取不到该属性的配置, 返回默认值true, 也就是默认会使用自动配置
		 */
		if (getClass() == AutoConfigurationImportSelector.class) {
			return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
		}
		// 如果当前类为其他类, 直接返回ture
		return true;
	}

从代码中可以看出,默认是会使用自动配置的。如果想覆盖或重置EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY的配置, 可在application.propertiesapplication.yml中针对参数spring.boot.enableautoconfiguration进行配置,如在application.properties配置关闭自动配置, 则设置

spring.boot.enableautoconfiguration=false。

3.2、loadMetadata方法

该方法会加载自动配置的元数据信息,使用的是AutoConfigurationMetadataLoader,从类名可以看出,是自动配置元数据加载器。

// 自动配置元数据加载
final class AutoConfigurationMetadataLoader {

	// 默认加载元数据的路径
	protected static final String PATH = "META-INF/spring-autoconfigure-metadata.properties";

	private AutoConfigurationMetadataLoader() {
	}

	// 加载元数据, 默认加载PATH(即类路径下META-INF/spring-autoconfigure-metadata.properties)中的配置
	static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
		return loadMetadata(classLoader, PATH);
	}

	static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
		try {
			// 获取数据并且存储于Enumeration中
			Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path)
					: ClassLoader.getSystemResources(path);
			Properties properties = new Properties();
			while (urls.hasMoreElements()) {
				// 遍历Enumeration中的URL, 加载其中的属性, 存储到Properties
				properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));
			}
			return loadMetadata(properties);
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);
		}
	}
  
  	// 创建AutoConfigurationMetadata的实现类PropertiesAutoConfigurationMetadata
	static AutoConfigurationMetadata loadMetadata(Properties properties) {
		return new PropertiesAutoConfigurationMetadata(properties);
	}

	// AutoConfigurationMetadata的内部实现类
	private static class PropertiesAutoConfigurationMetadata implements AutoConfigurationMetadata {
		...
  }
}

在上述代码中,AutoConfigurationMetadataLoader调用loadMetadata方法,获取默认变量PATH指定的文件,然后加载并存储在Enumeration数据机构中。随后,从文件中获取其中配置的数据存储于Properties内,最终调用在该类内部实现的AutoConfigurationMetadata的子类的构造方法。

spring-autoconfigure-metadata.properties文件内的配置格式如下:

自动配置类的全限定名.注解名称=值(如果文件内有多个值, 就用英文逗号隔开)

加载元数据是为了后续的过滤自动配置使用,Spring Boot使用一个Annotation的处理器来收集自动加载的条件,这些条件可以在元数据文件进行配置。Spring Boot会将收集好的@Configuration进行一次性过滤, 进而剔除不满足条件的配置类。官方文档显示,使用这种配置方式可以有效缩短Spring Boot的启动时间,减少@Configuration类的数量,从而减少初始化Bean的耗时。由于这块笔者还未接触到这块优化,对这个解释暂不清楚。

3.3、getAutoConfigurationEntry方法

该方法用于封装将要引入的自动配置信息,也是自动配置的核心。

	/**
	 * 封装将要引入的自动配置信息
	 */
	protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
			AnnotationMetadata annotationMetadata) {
    	// 再次检查自动配置功能是否开启
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
    	// 获取自动装配元数据信息的属性
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
    	// 通过SpringFactoriesLoader类提供的方法加载类路径中META-INF目录下的spring.factories文件中针对EnableAutoConfiguration的注册配置类
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    	// 对获得的注册配置类集合进行去重处理,防止多个项目引入同样的配置类
		configurations = removeDuplicates(configurations);
    	// 获取注解中被exclude或excludeName锁排除的类的集合
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    	// 检查被排除类是否可实例化,是否被自动注册配置所使用,不符合条件则抛出异常
		checkExcludedClasses(configurations, exclusions);
    	// 从自动配置类集合中去除被排除的类
		configurations.removeAll(exclusions);
    	// 检查配置类的注解是否符合spring.factories文件中AutoConfigurationImportFilter指定的注解检查条件
		configurations = filter(configurations, autoConfigurationMetadata);
    	// 将筛选完成的配置类和排查的配置类构建为事件类,并传入监听器。监听器的配置在spring.factories文件中,通过AutoConfigurationImportListener指定
    	// 并将事件类进行广播
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

3.3.1、getAttributes:获取自动装配元数据信息的属性

该方法会获取注解@EnableAutoConfiguration上的属性,用于后续排除部分组件。

protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
  		// 获取注解@EnableAutoConfiguration的类名
		String name = getAnnotationClass().getName();
    	// 获取注解@EnableAutoConfiguration上的属性
		AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
		Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
				+ " annotated with " + ClassUtils.getShortName(name) + "?");
		return attributes;
	}

	protected Class<?> getAnnotationClass() {
		return EnableAutoConfiguration.class;
	}

3.3.2、getCandidateConfigurations:加载自动配置组件

自动配置组件在类路径中META-INF目录下的spring.factories文件中进行注册,getCandidateConfigurations方法通过Spring Core提供的SpringFactoriesLoader类可以读取spring.factories文件中注册的类。

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
  		// loadFactoryNames会读取META-INF/spring.factories中的配置
  		// 由于第一个参数为EnableAutoConfiguration.class,则只会读取配置文件中针对自动配置的注册类
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				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;
	}

	protected Class<?> getSpringFactoriesLoaderFactoryClass() {
		return EnableAutoConfiguration.class;
	}

SpringFactoriesLoader中loadFactoryNames方法部分代码:

public final class SpringFactoriesLoader {

	// 该类加载文件的路径,可能存在多个
	public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

	...

	// 加载所有的META-INF/spring.factories文件,封装成Map,并根据指定类名进行筛选,获取特定的列表
	public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
		String factoryTypeName = factoryType.getName();
		return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
	}

  	// 加载所有的META-INF/spring.factories文件,封装成Map,Key为接口的全类名,Value为对应配置值的List集合
	private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
		...
	}

spring.factories文件中EnableAutoConfiguration配置的部分内容如下图所示:
在这里插入图片描述
由于程序默认加载的是ClassLoader下面的所有META-INF/spring.factories文件中的配置,所以难免在不同的jar包中出现重复的配置,则需要进行去重操作。

3.3.3、removeDuplicates:自动配置组件去重

去重很简单,通过Set集合去重。

protected final <T> List<T> removeDuplicates(List<T> list) {
		return new ArrayList<>(new LinkedHashSet<>(list));
}

3.3.4、getExclusions:获取需要排除的组件

前面介绍过可以通过配置@EnableAutoConfiguration的注解属性exclude或excludeName进行排除指定组件。

protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		Set<String> excluded = new LinkedHashSet<>();
		// 获取@EableAutoConfiguration注解中配置的exclude属性值
		excluded.addAll(asList(attributes, "exclude"));
		// 获取注解中配置的excludeName属性值
		excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
		// 获取配置文件中key为spring.autoconfigure.exclude的配置值
		excluded.addAll(getExcludeAutoConfigurationsProperty());
		return excluded;
}

private List<String> getExcludeAutoConfigurationsProperty() {
		if (getEnvironment() instanceof ConfigurableEnvironment) {
			Binder binder = Binder.get(getEnvironment());
			// PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE的值为spring.autoconfigure.exclude
			return binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class).map(Arrays::asList)
					.orElse(Collections.emptyList());
		}
		String[] excludes = getEnvironment().getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class);
		return (excludes != null) ? Arrays.asList(excludes) : Collections.emptyList();
	}

3.3.5、checkExcludedClasses:对排除的组件检查

	private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {
  		// 有问题的排除类集合
		List<String> invalidExcludes = new ArrayList<>(exclusions.size());
  		// 遍历并判断是否存在对应的配置类
		for (String exclusion : exclusions) {
			if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion)) {
				invalidExcludes.add(exclusion);
			}
		}
  		// 如果不为空, 则进行处理
		if (!invalidExcludes.isEmpty()) {
			handleInvalidExcludes(invalidExcludes);
		}
	}
	// 抛出异常
	protected void handleInvalidExcludes(List<String> invalidExcludes) {
		StringBuilder message = new StringBuilder();
		for (String exclude : invalidExcludes) {
			message.append("\t- ").append(exclude).append(String.format("%n"));
		}
		throw new IllegalStateException(String.format(
				"The following classes could not be excluded because they are not auto-configuration classes:%n%s",
				message));
	}

checkExcludedClasses方法用来确保被排除的类存在于当前ClassLoader中,并且包含在spring.factories注册的集合中。如果不满足这些条件,调用handleInvalidExcludes方法抛出异常。
如果被排除的类符合条件,调用configurations.removeAll(exclusions)方法从自动配置集合中移除被排除类的集合,完成初步的自动配置组件排除。

3.3.6、filter:过滤自动配置组件

   /**
	* 对自动配置类进行再次过滤
    * configurations:经过初次过滤之后的自动配置组件列表
    * autoConfigurationMetadata:元数据文件META-INF/spring-autoconfigure-metadata.properties中配置的实体类
	*/
	private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
		long startTime = System.nanoTime();
    	// 候选自动配置组件
		String[] candidates = StringUtils.toStringArray(configurations);
		boolean[] skip = new boolean[candidates.length];
		boolean skipped = false;
		// 遍历过滤器集合
		for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
      		// 判断是否为Aware的相关子类
			invokeAwareMethods(filter);
      		// 调用match判断是否匹配,参数1为待过滤的自动配置类数组,参数2为自动配置的元数据信息。
      		// 返回的结果为匹配过滤后的结果布尔数组,数组的大小与待过滤的自动配置类数组一致,如果需要排除,则设置对应的值为false
			boolean[] match = filter.match(candidates, autoConfigurationMetadata);
			for (int i = 0; i < match.length; i++) {
        		// 如果不匹配,则该索引位置置为空并设置跳过
				if (!match[i]) {
					skip[i] = true;
					candidates[i] = null;
					skipped = true;
				}
			}
		}
		if (!skipped) {
			return configurations;
		}
		List<String> result = new ArrayList<>(candidates.length);
    	// 将不跳过的自动配置组件生成新的集合返回
		for (int i = 0; i < candidates.length; i++) {
			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);
	}

	// 获取Filter列表
	protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
    // 跟前面类似,通过SpringFactoriesLoader的loadFactories方法加载文件META-INF/spring.factories中配置的key为AutoConfigurationImportFilter的过滤器
		return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
	}

META-INF/spring.factories文件中相关过滤器如下:

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

简述该filter方法的过程为:对自动配置组件列表再次过滤,过滤条件为该列表中自动配置类的注解得包含在OnBeanCondition、OnClassCondition、OnWebApplicationCondition中指定的注解,依次包含@ConditionalOnBean、@ConditionalOnClass和@ConditionalOnWebApplication。

3.3.6.1、match方法代码:

接口的match方法主要由其抽象子类FilteringSpringBootCondition实现,但是在实现时又定义了新的抽象方法getOutcomes。

public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
		ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);
    	// 进行匹配筛选,返回匹配结果
		ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
    	// 将匹配结果转换成布尔数组
		boolean[] match = new boolean[outcomes.length];
		for (int i = 0; i < outcomes.length; i++) {
			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);
3.3.6.2、OnClassCondition中的getOutcomes方法实现
protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
			AutoConfigurationMetadata autoConfigurationMetadata) {
		// 如果有多个处理器,采用后台线程处理
		if (Runtime.getRuntime().availableProcessors() > 1) {
			return resolveOutcomesThreaded(autoConfigurationClasses, autoConfigurationMetadata);
		}
		else {
			OutcomesResolver outcomesResolver = new StandardOutcomesResolver(autoConfigurationClasses, 0,
					autoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader());
			return outcomesResolver.resolveOutcomes();
		}
	}

整个过滤过程如下图所示:
在这里插入图片描述

3.3.7、fireAutoConfigurationImportEvents:事件注册并广播

在完成以上步骤的过滤、筛选后,获得了需要进行自动配置的类集合。在将该集合返回之前,需要对相关时间进行封装和广播。

private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
    	// 通过SpringFactoriesLoader提供的loadFactories方法将spring.factories中配置的接口AutoConfigurationImportListener的实现类加载出来
		List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
		if (!listeners.isEmpty()) {
      		// 将筛选出来的自动配置类集合和被排除的自动配置类集合封装成AutoConfigurationImportEvent事件对象
			AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
			for (AutoConfigurationImportListener listener : listeners) {
				invokeAwareMethods(listener);
        		// 将这些事件对象通过监听器提供的onAutoConfigurationImportEvent方法对事件进行广播
				listener.onAutoConfigurationImportEvent(event);
			}
		}
	}

	protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
		return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader);
	}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值