SpringBoot自动装配原理

@Import + @Configuration + Spring spi

Posted by Sunfy on 2021-10-06
Words 976 and Reading Time 4 Minutes
Viewed Times
Viewed Times
Visitors In Total

配置文件到底能写什么?怎么写?自动配置原理;

配置文件属性参照

SpringBoot自动装配

@Import + @Configuration + Spring spi

自动配置类由各个starter提供,使用@Configuration + @Bean定义配置类,放到META-INF/spring.factories下 使用Spring spi扫描META-INF/spring.factories下的配置类 使用@Import导入自动配置类

image-20210809172533498

  • 源码查看入口

    1
    public @interface SpringBootApplication
  • @SpringBootApplication: Spring Boot应用标注在某个类上说明这个类是Spring Boot的主配置类,Spring Boot需要运行这个类的main方法来启动Spring Boot应用;

  • @EnableAutoConfiguration 开启自动配置功能;自动扫描所有的配置类,扫描到并满足条件才会生效

    1
    2
    3
    4
    5
    6
    7
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {
    • @Import(AutoConfigurationImportSelector.class) SpringBoot实现自动配置的关键类

      1
      2
      3
      4
      5
      // 实现接口DeferredImportSelector(一个ImportSelector的变种,不会执行ImportSelector)
      // 解析@Import(AutoConfigurationImportSelector.class)注解时,调用getAutoConfigurationEntry
      public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
      ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
      // sunfy-AutoConf 自动配置重要入口
    • AutoConfigurationImportSelector 实现接口 DeferredImportSelector,判断是否重写getImportGroup方法,如果没有重写selectImports返回一个数组,将数组中的完整类名注册为bean

    • 重写getImportGroup方法,返回一个自定义的实现了DeferredImportSelector.Group的类
  • SpringBoot通过重写,返回自定义的DeferredImportSelector.Group的类

  • process中获取所有的配置并根据实际引入进行过滤

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @Override
    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()));
    AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
    // sunfy-autoConf 获取所有的有效自动配置类
    .getAutoConfigurationEntry(annotationMetadata);
    // selectImports 方法中获取到的配置
    this.autoConfigurationEntries.add(autoConfigurationEntry);
    for (String importClassName : autoConfigurationEntry.getConfigurations()) {
    this.entries.putIfAbsent(importClassName, annotationMetadata);
    }
    }

    getAutoConfigurationEntry获取所有有效自动配置类,进入方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // sunfy-autoConf 获取所有的有效自动配置类
    protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
    return EMPTY_ENTRY;
    }
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    // sunfy-autoconf 获取所有的配置类1XX个
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    configurations = removeDuplicates(configurations);
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    // sunfy-AutoConf 根据pom依赖中添加starter过滤出来的有效配置类
    configurations = getConfigurationClassFilter().filter(configurations);
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
    }

    getCandidateConfigurations中获取到SpringBoot项目中所有的Stater配置,总共有1xx多个

    image-20210118114003369

    进入getCandidateConfigurations方法中

    1
    2
    3
    4
    5
    6
    7
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    // sunfy-autoconf 加载所有配置文件,jar中可能都存在,都进行读取
    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;
    }

loadFactoryNames

1
2
3
4
5
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
// 要获取的自动配置类的全限定名
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

image-20210118210142763

loadSpringFactories

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
30
31
32
33
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
// 此时会尝试从缓存中进行获取,因为在SpringBoot启动时就会加载其他配置文件,因为加载所有的配置文件是一个很耗时耗内存的过程,在第一次加载完成后会放在cache中,方便后续获取
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}

try {
// public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
// 不难看出都会到对应的jar包中读取META-INF/spring.factories文件中的内容
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
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();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
// 将获取到的内容放入到缓存中
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}

image-20210118114603645

遍历每个jar包下的每个META-INF/spring.factories文件内容

image-20210118115041776

  1. getConfigurationClassFilter().filter(configurations)根据pom依赖中添加starter过滤出来的有效配置类

    至此所有的自动配置就全部获取到了


Copyright 2021 sunfy.top ALL Rights Reserved

...

...

00:00
00:00