SpringBoot自动配置原理源码解读
1.@SpringBootApplication:通过这个注解,不仅仅标记这是一个SpringBoot应用,而且还开启自动配置的功能
主要注解EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //主要功能自动配置包,他会获取主程序类所在包路径,并将包路径下的所有组件注册到Spring IOC 容器中
@Import(AutoConfigurationImportSelector.class) //AutoConfigurationImportSelector ,导入自动配置相关的资源
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
1.程序启动入口
SpringApplication.run(MVCApplication.class, args)
启动之后,无论是
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
还是
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
//最终都会调用SpringApplication(primarySources).run(args)
return new SpringApplication(primarySources).run(args);
}
都会从SpringApplication(primarySources).run(args)进入。
public ConfigurableApplicationContext run(String... args) {
//创建StopWatch对象,并启动,StopWatch主要用于简单统计run启动进程的时长
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// <2> 配置 headless 属性 这个和AWT有关,可以不看
configureHeadlessProperty();
// 获得 SpringApplicationRunListener 的数组,并启动监听
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
// <3> 创建 ApplicationArguments 对象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// <4> 加载属性配置。执行完成后,所有的 environment 的属性都会加载进来,包括 application.properties 和外部的属性配置。
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
// <5> 打印 Spring Banner
Banner printedBanner = printBanner(environment);
// <6> 创建 Spring 容器。
context = createApplicationContext();
// <7> 异常报告器
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// <8> 主要是调用所有初始化类的 initialize 方法
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// <9> 初始化 Spring 容器。
refreshContext(context);
// <10> 执行 Spring 容器的初始化的后置逻辑。默认实现为空。
afterRefresh(context, applicationArguments);
// <11> 停止 StopWatch 统计时长
stopWatch.stop();
// <12> 打印 Spring Boot 启动的时长日志。
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// <13> 通知 SpringApplicationRunListener 的数组,Spring 容器启动完成。
listeners.started(context);
// <14> 调用 ApplicationRunner 或者 CommandLineRunner 的运行方法。
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
// <14.1> 如果发生异常,则进行处理,并抛出 IllegalStateException 异常
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
// <15> 通知 SpringApplicationRunListener 的数组,Spring 容器运行中。
try {
listeners.running(context);
}
catch (Throwable ex) {
// <15.1> 如果发生异常,则进行处理,并抛出 IllegalStateException 异常
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
自动配置从 <9> 初始化 Spring 容器。refreshContext(context)进入。
private void refreshContext(ConfigurableApplicationContext context) {
// <1> 开启(刷新)Spring 容器
refresh(context);
// <2> 注册 ShutdownHook 钩子
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
开启Spring容器 refresh(context),进入process方法中
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
//<1>获得autoconfigurationEntry对象
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
//<2>添加到这个list中
this.autoConfigurationEntries.add(autoConfigurationEntry);
// <3> 添加到 entries 中
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
从<1>处获得获得autoconfigurationEntry对象,调用getAutoConfigurationEntry进入方法。
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
// <1> 判断是否开启。如未开启,返回空数组。
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// <2> 获得注解的属性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// <3> 获得符合条件的配置类的数组
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// <3.1> 移除重复的配置类
configurations = removeDuplicates(configurations);
// <4> 获得需要排除的配置类
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// <4.1> 校验排除的配置类是否合法
checkExcludedClasses(configurations, exclusions);
// <4.2> 从 configurations 中,移除需要排除的配置类
configurations.removeAll(exclusions);
// <5> 根据条件(Condition),过滤掉不符合条件的配置类
configurations = filter(configurations, autoConfigurationMetadata);
// <6> 触发自动配置类引入完成的事件
fireAutoConfigurationImportEvents(configurations, exclusions);
// <7> 创建 AutoConfigurationEntry 对象
return new AutoConfigurationEntry(configurations, exclusions);
}
<1>isEnabled首先判断是否开启自动配置
protected boolean isEnabled(AnnotationMetadata metadata) {
// 判断 "spring.boot.enableautoconfiguration" 配置判断,是否开启自动配置。
// 默认情况下(未配置),开启自动配置。
if (getClass() == AutoConfigurationImportSelector.class) {
return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
}
return true;
}
<2>getAttributes获得注解的属性
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
//此处 getAnnotationClass().getName() 返回的是 @EnableAutoConfiguration 注解,
// 所以这里返回的注解属性,只能是 exclude 和 excludeName 这两个。
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;
}
此处 getAnnotationClass().getName()
返回的是 @EnableAutoConfiguration
注解,所以这里返回的注解属性,只能是 exclude
和 excludeName
这两个。
<3>getCandidateConfigurations获得符合条件的配置类的数组,通过loadFactoryNames拿到所有名为META-INF/spring.factories的配置文件,然后按照factoryClass的名称取到对应的值
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//<1>加载指定类型EnableAutoConfigurations对应的,在META-INF/spring.factories 里类名的数组
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;
}
<3.1>removeDuplicates移除重复的配置类,直接使用LinkedHashSet去重
protected final <T> List<T> removeDuplicates(List<T> list) {
return new ArrayList<>(new LinkedHashSet<>(list));
}
<4>getExclusions获得需要排除的配置类
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
Set<String> excluded = new LinkedHashSet<>();
// 注解上的 exclude 属性
excluded.addAll(asList(attributes, "exclude"));
// 注解上的 excludeName 属性
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
// 配置文件的 spring.autoconfigure.exclude 属性
excluded.addAll(getExcludeAutoConfigurationsProperty());
return excluded;
}
主要就是![image-20200403195153713](/Users/zhaoyu/Library/Application Support/typora-user-images/image-20200403195153713.png)
![image-20200403195218472](/Users/zhaoyu/Library/Application Support/typora-user-images/image-20200403195218472.png)
找到注解上的和配置文件中的这个属性
<4.1>checkExcludedClasses检验排除的配置类是否合法
<4.2>configurations.removeAll(exclusions)移除需要排除的配置类
<5>filter(configurations, autoConfigurationMetadata)根据条件过滤掉不符合条件的配置类
<6>fireAutoConfigurationImportEvents(configurations, exclusions)触发自动配置类引入完成的事件
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
// <1> 加载指定类型 AutoConfigurationImportListener 对应的,在 `META-INF/spring.factories` 里的类名的数组。
List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
if (!listeners.isEmpty()) {
// <2> 创建 AutoConfigurationImportEvent 事件
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
// <3> 遍历 AutoConfigurationImportListener 监听器们,逐个通知
for (AutoConfigurationImportListener listener : listeners) {
// <3.1> 设置 AutoConfigurationImportListener 的属性
invokeAwareMethods(listener);
// <3.2> 通知
listener.onAutoConfigurationImportEvent(event);
}
}
}
process方法完成之后调用getImports()方法
public Iterable<Entry> getImports() {
Iterator var1 = this.deferredImports.iterator();
while(var1.hasNext()) {
ConfigurationClassParser.DeferredImportSelectorHolder deferredImport = (ConfigurationClassParser.DeferredImportSelectorHolder)var1.next();
this.group.process(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getImportSelector());
}
return this.group.selectImports();
}
}
关键是调用selectImports方法用于筛选需要引入的类名,获得要引入的配置类
public Iterable<Entry> selectImports() {
// <1> 如果为空,则返回空数组
if (this.autoConfigurationEntries.isEmpty()) {
return Collections.emptyList();
}
// <2.1> 获得 allExclusions
Set<String> allExclusions = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
// <2.2> 获得 processedConfigurations
Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
.collect(Collectors.toCollection(LinkedHashSet::new));
// <2.3> 从 processedConfigurations 中,移除排除的
processedConfigurations.removeAll(allExclusions);
// <3> 处理,返回结果
return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
.map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
.collect(Collectors.toList());
}
之后进入register,注册一个用于存储包名(package
)的 Bean 到 Spring IoC 容器中
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
// <1> 如果已经存在该 BEAN ,则修改其包(package)属性
if (registry.containsBeanDefinition(BEAN)) {
BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
}
// <2> 如果不存在该 BEAN ,则创建一个 Bean ,并进行注册
else {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(BasePackages.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN, beanDefinition);
}
}