SpringBootApplication注解
首先在我们的主启动类上面有@SpringBootApplication注解
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
点进注解查看,可以看到@SpringBootApplication是一个合成注解,与springboot有关的注解主要有三个
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan
@SpringBootConfiguration
SpringBootConfiguration注解其实就是一个Configuration注解,代表这是一个配置文件
@ComponentScan
ComponentScan定义了我们具体的包扫描规则,表示将那些包下的组件扫描进来
@EnableAutoConfiguration
SpringBoot的自动配置主要是这个注解,这个注解定义了我们SpringBoot自动装配的规则
其实EnableAutoConfiguration注解也是一个合成注解,与springboot有关的主要有两个注解:
- @AutoConfigurationPackage
- @Import({AutoConfigurationImportSelector.class})
@AutoConfigurationPackage
@AutoConfigurationPackage注解上有一个inport注解:@Import({Registrar.class}),导入了一个注册类
点进Registrar原码查看:
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
//AutoConfigurationPackages.PackageImports(metadata)).getPackageNames()
//得到的是SpringBootApplication所在类的包名
//这个方法就是将主程序启动类所在包下的所有组件注册进来
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
}
}
metadata就是我们AutoConfigurationPackage注解所在类的信息,由于SpringBootApplication是一个合成注解所以这里的metadata就是我们SpringBootApplication所在类的信息。
@Import({AutoConfigurationImportSelector.class})
点进AutoConfigurationImportSelector类中查看原码,可以看到几个主要方法:
这里记住annotationMetadata就是我们SpringBootApplication注解所在类的信息
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
selectImport调用getAutoConfigurationEntry方法获取自动配置信息。
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
//获取候选配置,加载META-INF/spring.factories文件中的jar包
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
//去重
configurations = this.removeDuplicates(configurations);
//删除需要排除的类
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
//进行过滤,并不是加载进来就必须使用
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
getAutoConfigurationEntry有一个关键方法就是getCandidateConfigurations
通过getCandidateConfigurations调用spring工厂的loadFactoryNames方法
//加载META-INF/spring.factories的实现
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
//factoryType为EnableAutoConfiguration的class信息
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
//这里获取的是EnableAutoConfiguration
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
任何一个springboot应用,都会引入spring-boot-autoconfigure,而spring.factories文件就在该包的下面
,spring.factories中的数据以key=value的形式存储
然后loadFactoryNames调用loadSpringFactories方法
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = cache.get(classLoader);
//首先检查缓存中是否有类加载器的对应信息,如果有直接返回缓存中的信息
if (result != null) {
return result;
}
//如果缓存中没有信息,就加载META-INF/spring.factories中的信息
result = new HashMap<>();
try {
//从META-INF/spring.factories中加载信息进行枚举遍历
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;
}
getCandidateConfigurations方法从spring-boot-autoconfigure中的META-INF/spring.factories文件中获取候选配置,然后进行去重,过滤等操作得到真正需要使用的配置信息
最后,如有错误还请指出