通过昨天的学习知道了启动SpringBoot项目是通过启动一个被@SpringBootApplication表示的类的main方法来启动的,启动时会加载自动装配类,来装配我们导入依赖的相关组件。今天就来大致看一下@SpringBootApplication是如何做到这些的。
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication
进入@SpringBootApplication,我们可以看到除去java自带的元注解外,@SpringBootApplication实际上是@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan的组合。
@ComponentScan是用于包扫描,进入@SpringBootConfiguration可以看到
@Configuration
@Indexed
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
是一个Spring的配置类。
剩下的@EnableAutoConfiguration应该就是实现@SpringBootApplication主要功能的注解。
进入@EnableAutoConfiguration
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class>[] exclude() default {};
String[] excludeName() default {};
}
除了元注解之外,它也被两个注解所修饰,先来看看@AutoConfigurationPackage
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
String[] basePackages() default {};
Class>[] basePackageClasses() default {};
}
可以看到它将Register类放入了Ioc容器中,这个Register类的功能是什么呢?
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
}
public Set
进来后我们看到它是AutoConfigurationPackages的一个静态内部类,实现了两个接口的方法。
从方法名registerBeanDefinitions我们可以猜测该方法时用来注册指定的Bean对象的,再看方法体。
AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0])
它获得了注解的元数据后,调用getPackageNames方法获取了报名并转化为了数组来进行注册。这也是为什么默认情况下SpringBoot会扫描main方法所在的包及其下级的包的原因。
对@AutoConfigurationPackage的分析先到这,接下来来看@Import({AutoConfigurationImportSelector.class})
它将AutoConfigurationImportSelector放入了容器,进入该类,通过debug我们定位到了getAutoConfigurationEntry方法,从方法名猜测,它是用来获得自动配置实体的方法
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set 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);
}
}
先进行判断,若不运行自动配置,则返回空,否则继续进行
首先获得了注解属性,接着获得了一个List型的configurations,紧接着对这个configurations做各种操作,可见
List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
是整个方法的重点。进入方法内部,发现它又调用了另一个方法来获取configurations
protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}
继续深入
public static List loadFactoryNames(Class> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoader == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
首先获得类加载器,若为空,则重新获取。
最后通过(List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());获取返回的configurations
private static Map> loadSpringFactories(ClassLoader classLoader) {
Map> result = (Map)cache.get(classLoader); //首先从缓存中查询
if (result != null) {
return result; //若缓存中有,则返回
} else {
HashMap result = new HashMap(); //若没有,则新建一个HashMap进行封装
try {
Enumeration urls = classLoader.getResources("META-INF/spring.factories");//获取所有META-INF/spring.factors的信息
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[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
String[] var10 = factoryImplementationNames;
int var11 = factoryImplementationNames.length;
for(int var12 = 0; var12 < var11; ++var12) {
String factoryImplementationName = var10[var12];
((List)result.computeIfAbsent(factoryTypeName, (key) -> {
return new ArrayList();
})).add(factoryImplementationName.trim());
}
}
}
result.replaceAll((factoryType, implementations) -> {
return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
});
cache.put(classLoader, result); //获取结束后,放入缓存中一份
return result; //并返回
} catch (IOException var14) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
}
}
}
随便打开一个META-INF/spring.factories文件,发现里面是各种含有AutoConfiguration后缀的信息
随便打开一个AutoConfiguration后缀的文件,发现其为配置文件,并写出了各种初始信息
我们猜测,SpringBoot再获得result后,会一个个对这些AutoConfiguration进行解析,并将其放入Ioc容器中,这样就实现了自动装配。