为了方便测试,自定义了一个SprongBootStarter
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.sgg.aopcache.cache.conf.RedissonAotoConfiguration
注解的元信息
@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 看名字就知道 开启自动配置
好,点进去这个注解
首先看下这个注解的元信息和属性
@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() 如果需要排除某些自动配置类 可以给这两个参数设置值
最重要的看这个注解
@Import注解将某个组件导入spring容器中
我们看下 AutoConfigurationImportSelector 这个类都干了什么事情
找到这个方法 selectImports
调用了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);
}
getBeanClassLoader()
可以看到这个方法的第二个参数获取了类加载器 想想我们自定义starter 的META-INF 文件夹是放在哪里的?
放在resource目录下,这个目录的路径由谁加载,由 AppClassLoader负责加载
点进loadFactoryNames 方法
获取了 @EnableAutoConfiguration 注解的全限定类名
首先执行这个方法 loadSpringFactories(classLoader) 注意把类加载器传进去了
这个方法返回一个 Map
然后再调用它的 .getOrDefault(factoryTypeName, Collections.emptyList()) 方法 也就是获取key = factoryTypeName 的value
而value 是一个String类型的集合 也就是自动配置类的全限定类名
我们跟进这个方法看一下
重点看这个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.factories 配置文件,我们一般只会写 org.springframework.boot.autoconfigure.EnableAutoConfiguration= xxxx
而springboot官方的starter不单单只有
org.springframework.boot.autoconfigure.EnableAutoConfiguration
所以在这我们打断点多循环几次
最后可以看到 我们自定义starter 的 spring.factories文件信息已经被放到了 LinkedMultiValueMap result 中 并返回
返回前还将数据都放到了缓存中
至此,候选的自动配置类全限定类名都已经拿到了,之后还要经历筛选和过滤
最终返回经过了排除和过滤的自动配置类的全限定名数组