揭密springboot自动装配(2)--AutoConfigurationImportSelector

 

我们从启动类里的@SpringBootApplication注解开始


里面有三个主要注解

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan

这里自动装配的主要注解是@EnableAutoConfiguration这个,我们跟进去看看

会发现这里面有引入我们上章提到的神秘东东AutoConfigurationImportSelector

揭密springboot自动装配(2)--AutoConfigurationImportSelector_第1张图片

继续跟进AutoConfigurationImportSelector一探究竟,它是实现DeferredImportSelector,这个里面继承了ImportSelector

我们来看看他的selectImports方法实现

@Override
  public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
      return NO_IMPORTS;
    }
    AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
        .loadMetadata(this.beanClassLoader);
    AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
        annotationMetadata);
    return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
  }

这里面我们关注getAutoConfigurationEntry继续跟进去

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
      AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
      return EMPTY_ENTRY;
    }
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    List configurations = getCandidateConfigurations(annotationMetadata, attributes);
    configurations = removeDuplicates(configurations);
    Set exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    configurations = filter(configurations, autoConfigurationMetadata);
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
  }

继续跟进getCandidateConfigurations这个方法

  protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List 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;
  }

到这里你会发现有这么句话No auto configuration classes found in META-INF/spring.factories,

META-INF/spring.factories这个文件是不是有点熟悉,先放着,继续跟进就会明白了

public static List loadFactoryNames(Class factoryType, @Nullable ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }
private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                Enumeration urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                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[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;

                        for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryImplementationName = var9[var11];
                            result.add(factoryTypeName, factoryImplementationName.trim());
                        }
                    }
                }

                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
            }
        }
    }

直到这里你会发现,他就是加载了所有META-INF/spring.factories文件下的数据,我们随便点开一个META-INF/spring.factories看看

揭密springboot自动装配(2)--AutoConfigurationImportSelector_第2张图片

这里面就有很多需要自动装配的key-value对,到这里我们就应该能猜到大概实现了

这里loadFactoryNames就是获取对应EnableAutoConfiguration.class也就是对应上面spring.factories文件里的key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的所有value值也就是class路径

protected Class getSpringFactoriesLoaderFactoryClass() {
		return EnableAutoConfiguration.class;
	}

我们重新回到selectImports方法

揭密springboot自动装配(2)--AutoConfigurationImportSelector_第3张图片

到这里我们就很清楚这里返回的就是所有在spring.factories文件里key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的所有value值class路径,印证上一章中的例子,我们下面回顾下:

揭密springboot自动装配(2)--AutoConfigurationImportSelector_第4张图片

同样这里是不是可以启发我们,将配置类写在META-INF/spring.factories文件里,然后key写为

org.springframework.boot.autoconfigure.EnableAutoConfiguration

是不是也可以自动帮我们给装配进去,例如下面这样我们在自己项目中创建META-INF/spring.factories,我们自动装配UserA

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.demo.service.UserA

这样我们也是一样可以在spring容器中可以拿到我们的UserA;

ok,基本的实现流程我们已经了解大概了,那到这里应该还是会有个疑问,哪个地方调用selectImports方法?

下章我们就这个问题进行分析

 

你可能感兴趣的:(springBoot)