概述
面试中频率非常高的一个问题:Spring Boot如何实现自动配置?或其原理是什么?
如何简洁而又条理地抓住重点来回答这个问题,其实有点难。
必须要提到的几个要点:
- 约定优于配置:Convention over Configuration,通过扫描类路径上的依赖和现有的 Bean 定义,动态地为应用提供合理的默认配置;
- @EnableAutoConfiguration注解:通过启动类上的@SpringBootApplication引入;
AutoConfigurationImportSelector.selectImports()
:动态加载配置类;- 条件注解:根据类路径依赖、现有Bean、属性配置等条件决定是否启用某些配置;
spring.factories
文件:基于SPI机制;AutoConfiguration.imports
文件:Spring Boot 3.0版本后推荐的方式。
原理
分析自动配置原理的入口是启动类,启动类使用@SpringBootApplication,这是一个组合注解,包括@EnableAutoConfiguration。
另外,自动配置源码在spring-boot-autoconfigure-3.2.4.jar
,即,本文基于Spring Boot 3.2.4版本。
EnableAutoConfiguration
该注解的源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {
};
String[] excludeName() default {
};
}
面对一个注解类,对其进行分析,要从两个地方入手:
- 添加的注解:如@Target、@AutoConfigurationPackage等。
- 属性:如exclude;
@Target等4个注解可略过,不清楚可参考Java基础之注解。
@AutoConfigurationPackage,作用是将添加该注解的类所在的package作为自动配置package进行管理。
@Import,作用是将所有符合自动配置条件的Bean定义加载到Spring IoC容器。看注解时,还得看其参数,此处为AutoConfigurationImportSelector.class
,请看后文。
此注解有两个属性exclude
和excludeName
,功能定位几乎相同,都是用于排除自动配置生效类,具体代码看getExclusions方法。
此外,还有个字段,ENABLED_OVERRIDE_PROPERTY
在AutoConfigurationImportSelector.selectImports()
方法里用于判断自动配置是否生效:
protected boolean isEnabled(AnnotationMetadata metadata) {
if (getClass() == AutoConfigurationImportSelector.class) {
return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
}
return true;
}
AutoConfigurationImportSelector
看一下源码:
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
// 关闭自动配置时返回空Entry
private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();
// 关闭自动配置时返回空数组
private static final String[] NO_IMPORTS = {
};
// 用于排除自动配置类
private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
//
private ConfigurableListableBeanFactory beanFactory;
//
private Environment environment;
// 类加载器
private ClassLoader beanClassLoader;<