@SpringBootApplication
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {}
@ComponentScan
这个注解作用:排除或者加载或者自定义过滤规则将自定义的类,加入到Spring容器中
@EnableAutoConfiguration
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
重点是:
AutoConfigurationImportSelector 类
这个类的父类的父类是:ImportSelector。主要 接口是 selectImports。也就是说,重点看 AutoConfigurationImportSelector#selectImports
看方法:
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 是否开启自动注入,否的话,返回一个空数组
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 获取要 被spring 容器,管理的javaBean。先从 META-INF/spring.factories 加载之后,经过一系列操作,完成 Spring容器的初始化
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
getAutoConfigurationEntry 方法
Entry–中文,入口的意思
/**
* Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}
* of the importing {@link Configuration @Configuration} class.
* @param annotationMetadata the annotation metadata of the configuration class
* @return the auto-configurations that should be imported
*/
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 1-获取注解属性,若获得的是null,将抛出异常
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//2-去得到 下META-INF/spring.factories 定义的类实例(一般较多,需要经过后续去重,去排除,过滤等操作)
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//3- 去重
configurations = removeDuplicates(configurations);
//4-得到要排除的集合
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
//5-检查排除的类
checkExcludedClasses(configurations, exclusions);
//5-去掉排除的类
configurations.removeAll(exclusions);
//6-过滤。重点
configurations = getConfigurationClassFilter().filter(configurations);
//7-
fireAutoConfigurationImportEvents(configurations, exclusions);
//8-
return new AutoConfigurationEntry(configurations, exclusions);
}
1-getAttributes方法
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
String name = getAnnotationClass().getName();
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;
}
2-getCandidateConfigurations 方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 下面这句话是:重点
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;
}
重点:SpringFactoriesLoader类
这个是:读取,spring.factories文件,并实例化,最终要放到IOC容器中
把这jar 下的 META-INF/spring.factories,key = EnableAutoConfiguration的进行实例化!
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
result = new HashMap<>();
try {
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
}
}
// Replace all lists with unmodifiable lists containing unique elements
result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
cache.put(classLoader, result);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
return result;
}
6-过滤
点进去方法
List<String> filter(List<String> configurations) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean skipped = false;
for (AutoConfigurationImportFilter filter : this.filters) {
// 重点:看autoConfigurationMetadata
boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
是个内部类。看构造器
去load “META-INF/spring-autoconfigure-metadata.properties”; 这个文件的内容
这个文件很大。
举个例子
// configurations 在过滤之前是 270个 。过滤之后,只有 120个了
configurations = getConfigurationClassFilter().filter(configurations);