【Spring Boot】Spring Boot 自动配置原理 图文并茂

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第1张图片

为了方便测试,自定义了一个SprongBootStarter

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.sgg.aopcache.cache.conf.RedissonAotoConfiguration

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第2张图片

1.@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) })

看这个注解 @EnableAutoConfiguration 看名字就知道 开启自动配置

好,点进去这个注解

2. @EnableAutoConfiguration 开启自动配置注解

首先看下这个注解的元信息和属性

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

	/**
	 * Environment property that can be used to override when auto-configuration is
	 * enabled.
	 */
	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 {};

}

exclude() excludeName() 如果需要排除某些自动配置类 可以给这两个参数设置值

最重要的看这个注解

3.@Import(AutoConfigurationImportSelector.class)

@Import注解将某个组件导入spring容器中

我们看下 AutoConfigurationImportSelector 这个类都干了什么事情

找到这个方法 selectImports

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第3张图片

调用了getAutoConfigurationEntry 方法

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		List configurations = getCandidateConfigurations(annotationMetadata, attributes);
		configurations = removeDuplicates(configurations);
		Set exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第4张图片

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第5张图片

getBeanClassLoader()

可以看到这个方法的第二个参数获取了类加载器 想想我们自定义starter 的META-INF 文件夹是放在哪里的?

放在resource目录下,这个目录的路径由谁加载,由 AppClassLoader负责加载

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第6张图片

点进loadFactoryNames 方法

4. SpringFactoriesLoader.loadFactoryNames

image-20220317231256193

获取了 @EnableAutoConfiguration 注解的全限定类名

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第7张图片

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第8张图片

首先执行这个方法 loadSpringFactories(classLoader) 注意把类加载器传进去了

这个方法返回一个 Map

然后再调用它的 .getOrDefault(factoryTypeName, Collections.emptyList()) 方法 也就是获取key = factoryTypeName 的value

而value 是一个String类型的集合 也就是自动配置类的全限定类名

我们跟进这个方法看一下

5.loadSpringFactories(classLoader)

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第9张图片

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第10张图片

重点看这个else代码块都做了什么事

 Enumeration urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry entry = (Entry)var6.next();
                        String factoryTypeName = ((String)entry.getKey()).trim();
                        String[] var9 = 		StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;

                        for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryImplementationName = var9[var11];
                            result.add(factoryTypeName, factoryImplementationName.trim());
                        }
                    }
                }

                cache.put(classLoader, result);
                return result;

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第11张图片

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第12张图片

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第13张图片

如果是我们自定义的 spring.factories 配置文件,我们一般只会写 org.springframework.boot.autoconfigure.EnableAutoConfiguration= xxxx

而springboot官方的starter不单单只有

org.springframework.boot.autoconfigure.EnableAutoConfiguration

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第14张图片

所以在这我们打断点多循环几次

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第15张图片

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第16张图片

最后可以看到 我们自定义starter 的 spring.factories文件信息已经被放到了 LinkedMultiValueMap result 中 并返回

返回前还将数据都放到了缓存中

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第17张图片

至此,候选的自动配置类全限定类名都已经拿到了,之后还要经历筛选和过滤

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第18张图片

最终返回经过了排除和过滤的自动配置类的全限定名数组

【Spring Boot】Spring Boot 自动配置原理 图文并茂_第19张图片

你可能感兴趣的:(SpringBoot,spring,boot,spring,java)