之前对 SpringBoot 的自动配置原理进行了较为详细的介绍(https://www.cnblogs.com/stm32stm32/p/10560933.html), 接下来就对自动配置进行源码调试, 探究下这个配置过程中各参数的情况.
这里对 AutoConfigurationImportSelector 类的 selectImports()方法打了 4 处断点, 将着重对这 4 处进行调试.
第一处断点:
该方法的源码如下:
这一步就是将 META-INF/spring-autoconfigure-metadata.properties 文件中的键值对放入 AutoConfigurationMetadataLoader 的内部类 PropertiesAutoConfigurationMetadata 的 Properties 对象中, 共有 485 个元素.
第二处断点:
这个方法的源码如下:
其中的 name 就是 org.springframework.boot.autoconfigure.EnableAutoConfiguration 类:
下面的方法中的 metadata.getAnnotationAttributes(name, true)获取到的值如下:
这里还利用断言进行 attributes 是否为 null 判断, 若为 null, 则提示 No auto-configuration attributes found. Is com.SpringboothuifuApplication annotated with EnableAutoConfiguration ?
最终得到的 attributes 为:
第三处断点:
getCandidateConfigurations 方法定义如下:
其中的 getSpringFactoriesLoaderFactoryClass()返回的是 EnableAutoConfiguration.class.
进入 loadFacotryNames()方法进行调试:
factoryClassName 的值为 org.springframework.boot.autoconfigure.EnableAutoConfiguration.
常量 FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories".
下面的方法通过类加载器获取 jar 包中所有 META-INF/spring.factories 并获取其中的内容:
最后的 urls 包含扫描到 3 个 jar 包中有 spring.factories 文件:
接下来对 urls 进行 3 次遍历:
第一次遍历的文件路径 url=jar:file:/C:/Users/Alan/.m2/repository/org/springframework/boot/spring-boot/1.5.17.RELEASE/spring-boot-1.5.17.RELEASE.jar!/META-INF/spring.factories
通过 Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url)); 得到的 properties 对象的大小为 7:
因为上述 properties 并不存在 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的 key,
所以 String factoryClassNames = properties.getProperty(factoryClassName); 得到的 factoryClassNames 为 null
此时存放自动配置类的 list 集合 result 的大小仍然为 0.
第二次遍历的文件路径 url=jar:file:/C:/Users/Alan/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/1.5.17.RELEASE/spring-boot-autoconfigure-1.5.17.RELEASE.jar!/META-INF/spring.factories
该文件也有 7 个键值对, 新生成的 properties 大小为 7:
此时 properties.getProperty(factoryClassName)将能找到 key=org.springframework.boot.autoconfigure.EnableAutoConfiguration 的属性键值对.
factoryClassNames 此时包含了 org.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的 value 值, 最后全部添加到 list 集合里面, 共有 96 个值(Arrays.asList 转换得到):
第三次遍历 jar:file:/C:/Users/Alan/.m2/repository/org/springframework/spring-beans/4.3.20.RELEASE/spring-beans-4.3.20.RELEASE.jar!/META-INF/spring.factories
但是里面仍然没有 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的 key, 所以 result 里面并没有添加新元素.
总共进行了 3 次遍历, 分别是下面 3 个 jar 包包含 spring.factories 文件:
- ,spring-boot-1.5.17.RELEASE.jar
- ,spring-boot-autoconfigure-1.5.17.RELEASE.jar
- ,spring-beans-4.3.20.RELEASE.jar
而上述 3 个 jar 的 spring.factories 只有 spring-boot-autoconfigure-1.5.17.RELEASE.jar 中包含 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的 key, 这样就把需要自动配置的候选类都找出并放入 list 集合中.
接着还会用断言判断 configurations 是否有元素, 否则提示: No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.
最后返回自动配置类的 list 集合对象 configurations.
第四处断点:
filter 方法传入了 2 个参数:
1,configurations: 读取 MEAT-INF/spring.factories 文件得到的经过排除得到的自动配置类名的 list 集合
2,autoConfigurationMetadata: 读取 META-INF/spring-autoconfigure-metadata.properties 文件得到的 485 个键值对.
候选自动配置类数组 candidates 由 configurations 转数组而来: String[] candidates = configurations.toArray(new String[configurations.size()]); 其值如下:
for 循环中的 getAutoConfigurationImportFilters 定义如下:
里面的 SpringFactoriesLoader.loadFactories()方法定义如下:
上述方法主要目的是找寻 spring.factories 文件中 key=org.springframework.boot.autoconfigure.AutoConfigurationImportFilter 对应的值,
这里依然进行了 3 次遍历, 分别是下面 3 个 jar 包包含 spring.factories 文件
- ,spring-boot-1.5.17.RELEASE.jar
- ,spring-boot-autoconfigure-1.5.17.RELEASE.jar
- ,spring-beans-4.3.20.RELEASE.jar
而上述 3 个 jar 的 spring.factories 只有 spring-boot-autoconfigure-1.5.17.RELEASE.jar 中包含了 org.springframework.boot.autoconfigure.AutoConfigurationImportFilter 的 key.
通过 loadFactoryNames(factoryClass, classLoaderToUse)得到的 factoryNames 为 org.springframework.boot.autoconfigure.condition.OnClassCondition 类.
接着遍历 factoryNames, 调用 instantiateFactory 方法, 利用反射生成 condition.OnClassCondition 的实例添加到 result 集合中:
最后对 result 进行排序并返回: AnnotationAwareOrderComparator.sort(result);
getAutoConfigurationImportFilters()分析完了, 我们继续看 for 循环:
上面的 invokeAwareMethods(filter)方法根据 filter 是否实现了相关接口, 对其进行了设置:
filter 满足 instance instanceof Aware,instance instanceof BeanClassLoaderAware,instance instanceof BeanFactoryAware.
接下来我们着重看下 match 方法:
上述方法调用了 OnClassCondition 类的 match 方法:
传入的参数是之前排除过自动配置类, 目前还有 96 个:
下面的方法利用 autoConfigurationMetadata 对象对 autoConfigurationClasses 进行处理, autoConfigurationMetadata 是加载 META-INF/spring-autoconfigure-metadata.properties 得到的 485 个元素, autoConfigurationClasses 是读取 META-INF/spring.factories 文件 key 为 org.springframework.boot.autoconfigure.EnableAutoConfiguration 得到值进行排除, 排序, 去重等操作得到的候选自动配置类(由于没有添加排除项, 目前仍然有 96 个).
getOutComes 定义如下:
该方法将自动候选配置类分成 2 半进行条件判断处理, outcomes 存入的是条件判断后的结果:
匹配结束后的 ConditionEvaluationReport 对象 report 存放了不匹配的结果, 从结果中看到候选的 96 个自动配置类, 有 72 个不满足条件而被过滤:
随便点开一个 outcomes 元素:
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration -> key=org.springframework.boot.autoconfigure.aop.AopAutoConfiguration;
匹配失败原因:@ConditionalOnClass did not find required classes 'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice'
由于项目没有引入 aop 的相关依赖, 导致类路径中没有 Aspect 和 Advice 类, 导致 AopAutoConfiguration 这个自动配置类匹配失败.
(1) META-INF/spring-autoconfigure-metadata.properties 文件中的 Aop 内容:
- org.springframework.boot.autoconfigure.aop.AopAutoConfiguration.Configuration=
- org.springframework.boot.autoconfigure.aop.AopAutoConfiguration=
- org.springframework.boot.autoconfigure.aop.AopAutoConfiguration.ConditionalOnClass=
- org.springframework.context.annotation.EnableAspectJAutoProxy,org.aspectj.lang.annotation.Aspect,org.aspectj.lang.reflect.Advice
(2) META-INF/spring.factories 中的 Aop 内容:
- org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
因此 spring.factories 中的 key=org.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的值只是候选的自动配置类;
能否成功配置, 关键还要看是否已经被排除以及是否满足 spring-autoconfigure-metadata.properties 中对对应配置类的加载条件.
若不满足, 则该类是会从自动配置类列表中排除, 这样能加快 springboot 的启动速度. spring 官方文档 () 对该文件的作用描述如下:
Spring Boot uses an annotation processor to collect the conditions on auto-configurations in a metadata file (META-INF/spring-autoconfigure-metadata.properties). If that file is present, it is used to eagerly filter auto-configurations that do not match, which will improve startup time.
然后根据匹配结果, 将真正满足配置条件的配置类放入 list 集合中 boolean[] skip 记录了对应的候选自动配置类是否需要跳过, true - 不满足条件, 需要跳过, false - 满足条件, 不需要跳过.
for 循环结束, 只有 24 个自动配置真正符合条件:
因此第四处断点走完, 真正符合自动配置条件类的自动配置类只有 24 个了(根据项目配置情况会有所不同):
至此, SpringBoot 自动配置源码调试告一段落, 总结如下:
1, 读取 META-INF/spring-autoconfigure-metadata.properties 文件中的内容;
2, 获取需要排除的自动配置类;
3, 读取 spring-boot-autoconfigure-1.5.17.RELEASE.jar 中的 META-INF/spring.factories 文件内容, 作为候选自动配置类;
4, 对候选自动配置类进行去重, 排序, 去除所有排除项;
5, 利用 META-INF/spring-autoconfigure-metadata.properties 文件的配置对 META-INF/spring.factories 经历第四步处理后的候选自动配置类进行过滤, 去除不满足加载条件的类, 得到最终的自动配置类供 SpringBoot 加载.
来源: https://www.cnblogs.com/stm32stm32/p/10575145.html