spring boot自动配置原理

关于springboot的自动配置原理,是非常非常非常重要的知识点,应该牢记和熟悉其原理!!!!!!!!!!

如果学过SpringMVC,一定有被XML 配置统治的恐惧。这也就是为什么SpringMVC被称为配置地狱。但是,Spring Boot 项目,我们只需要添加相关依赖,无需配置,通过启动下面的 main 方法即可。

1
2
3
4
5
6
7
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

自动装配可以说是springboot的核心。springboot自动配置原理就是当spring容器启动时候,一些配置类、、bean对象就自动存入IOC容器中,不需要我们手动申明,从而简化了开发,省去了繁琐的配置操作。

SpringBoot是如何实现自动装配的?

每一个启动类上都有springboot的核心注解SpringBootApplication。点进SpringBootApplication之后:

1
2
3
4
5
6
7
8
9
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {...}

@SpringBootApplication封装了@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个注解

@SpringBootApplication是springboot中最重要的注解

·@SpringBootConfiguration:底层封装了@Configuration注解,用来声明配置类

·@EnableAutoConfiguration:springboot实现自动化配置的核心注解

·@ComponentScan:组件扫描

@EnableAutoConfiguration 是实现自动装配的重要注解,我们以这个注解入手

@EnableAutoConfiguration:实现自动装配的核心注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

/**
* Environment property that can be used to override when auto-configuration is
* enabled.
*/
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};

/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};

}

@EnableAutoConfiguration 引入了@Import,自动装配核心功能的实现实际是通过 AutoConfigurationImportSelector类。

AutoConfigurationImportSelector:加载自动装配类

AutoConfigurationImportSelector类的继承体系如下:

1
2
3
4
5
6
7
8
9
10
11
12
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {

}

public interface DeferredImportSelector extends ImportSelector {

}

public interface ImportSelector {
String[] selectImports(AnnotationMetadata var1);
}

可以看出,AutoConfigurationImportSelector 类实现了 ImportSelector接口,也就实现了这个接口中的 selectImports方法,该方法主要用于获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中

1
2
3
4
5
6
7
8
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

其中getAutoConfigurationEntry()方法,这个方法主要负责加载自动配置类的。它会获取所有有效的自动配置类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
// 判断 enableautoconfiguration注解有没有开启,默认开启(是否进行自动装配)
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 用于获取EnableAutoConfiguration注解中的 exclude 和 excludeName。
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 获取所有默认支持的自动配置类名列表
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 去除重复的配置类,自己写的starter 可能存在重复的
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 校验排除类(exclusions指定的类必须是自动配置类,否则抛出异常)
checkExcludedClasses(configurations, exclusions);
// 从 configurations 中,移除所有不希望自动配置的配置类
configurations.removeAll(exclusions);
// 筛选候选的自动配置类,根据项目pom.xml中加入的依赖筛选出最终符合当前项目运行环境对应的自动配置类
// 判断是否要加载某个类的两种方式:
// 根据spring-autoconfigure-metadata.properties进行判断。
// 判断@Conditional是否满足
configurations = getConfigurationClassFilter().filter(configurations);
// 过滤完成后会自动加载类路径下Jar包中META-INF/spring.factories文件中 AutoConfigurationImportListener的实现类,
// 并触发fireAutoConfigurationImportEvents事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}

其中getCandidateConfigurations方法用于获得所有的配置类,点击这个方法之后可以看到:

1
2
3
4
5
6
7
8
9
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = new ArrayList<>(
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}

通过调用loadFactoryNames:

1
2
3
4
5
6
7
8
9
public static List<String> 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());
}

其中最终loadSpringFactories获取需要自动装配的所有配置类,读取META-INF/spring.factories

image-20231216135721309

然后对加载到的所有配置类进行过滤,因为很多自动配置类都有条件注解;当条件注解@ConditionalOnXXX 中的所有条件都满足,该类才会生效。

image-20231216141730098

总结

  1. 通过@SpringBootApplication 引入**@EnableAutoConfiguration**(负责启动自动配置功能)
  2. @EnableAutoConfiguration 引入**@Import** 加载AutoConfigurationImportSelector
  3. Spring容器启动时:加载Ioc容器会解析Import注解
  4. @Import导入了一个DeferredImportSelector(它会使SpringBoot自动配置类的顺序在最后,这样方便我们扩展和覆盖)
  5. 然后读取所有的**/META-INF/spring.factories**文件(SPI)
  6. 过滤出所有AutoConfigurtionClass类型的类
  7. 最后通过**@ConditionXXX**排除无效的自动配置类