哎呦,不错超详细的SpringBoot自动装配原理剖析(下)

@SpringBootApplication注解对这个注解详细大家一定非常熟悉了 。 再来好好看看这个注解 。
我们点进该注解 , 发现它由多个注解构成 。 这种注解 注解注解的方式实在看着让人头疼
哎呦,不错超详细的SpringBoot自动装配原理剖析(下)文章插图

  • @ComponentScan 就不多赘述了 , 就是一个自动扫描的注解 。 应该都很熟悉
我们主要看这两个SpringBoot的注解 , 也就是 @SpringBootConfiguration和@EnableAutoConfiguration
我们点进 @SpringBootConfiguration注解发现他里面没有太多东西 , 只是对 @Configuration注解进行了一个封装 。
简而言之 , 它就是一个 @Configuration 注解而已 。
哎呦,不错超详细的SpringBoot自动装配原理剖析(下)文章插图
那只剩下@EnableAutoConfiguration注解可以做文章了 , 该注解水特别深
点进该注解后 , 我们看到有 @AutoConfigurationPackage和 @Import两个注解
哎呦,不错超详细的SpringBoot自动装配原理剖析(下)文章插图
  • @AutoConfigurationPackage注解没什么好说的 , 和它的名字一样其作用就是自动配置包 。 也就是让该注解标记的类所在包及下面所有子包里面的所有组件扫描到Spring容器中 。
  • @Import注解则导入了一个AutoConfigurationImportSelector类 , 我们点进去看一下这个类做了什么 。
发现该类实现了许多接口 , 我们把目光放到 DeferredImportSelector接口上 , 点进这个接口 , 发现它继承了ImportSelector接口 。 再往里点 , 发现ImportSelector接口 它有一个selectImports方法 , 到头了 。
哎呦,不错超详细的SpringBoot自动装配原理剖析(下)文章插图
我们回到AutoConfigurationImportSelector类 , 看看selectImports这个方法被如何重写了 。
哎呦,不错超详细的SpringBoot自动装配原理剖析(下)文章插图
首先 if判断会确认系统是否禁用了自动配置的功能 。 如果禁用了就会 return一个常量 , 该常量是一个空数组 。 也就无法注入bean了 。
哎呦,不错超详细的SpringBoot自动装配原理剖析(下)文章插图
再往下能看到调用了一个 getAutoConfigurationEntry方法 , 我们看看这个方法干了什么 。
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {// 判断是否允许自动装配 若不允许则直接返回空集 默认返回true if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY; }//getAttributes方法获得 @EnableAutoConfiguration注解中的属性exclude、excludeName等 。AnnotationAttributes attributes = getAttributes(annotationMetadata);// ==又一关键方法== 该方法用于得到spring.factories文件EnableAutoConfiguration相关的自动配置类 List configurations = getCandidateConfigurations(annotationMetadata, attributes);// 移除重复的配置类 configurations = removeDuplicates(configurations);// 得到要排除的自动配置类 Set exclusions = getExclusions(annotationMetadata, attributes);// 检查要被排除的配置类 checkExcludedClasses(configurations, exclusions);// 将要排除的配置类全部移除 configurations.removeAll(exclusions);// 过滤操作 , 避免内存浪费 configurations = getConfigurationClassFilter().filter(configurations);// 获取了符合条件的自动配置类后通知监听器来记录符合条件的自动配置类 fireAutoConfigurationImportEvents(configurations, exclusions);// 将符合条件和要排除的自动配置类封装进AutoConfigurationEntry对象 , 并返回 return new AutoConfigurationEntry(configurations, exclusions);}复制代码AutoConfigurationEntry方法主要用来获取符合条件的自动配置类 , 和避免加载不需要的自动配置类(会造成内存的浪费) 。
我们再来看看用于得到所有自动配置类的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;}复制代码是不是又看到一个十分熟悉的方法loadFactoryNames();, 我们把镜头交到loadFactoryNames , 再回顾一遍 SpringBoot是如何从 META-INF/spring.factories中加载指定 key的 value的 。
public static List loadFactoryNames(Class factoryType, @Nullable ClassLoader classLoader) {// 获取检索类的全限定名String factoryTypeName = factoryType.getName();// 进行spring.factories文件集的加载、检索操作 , 并构以空集为兜底返回数据return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());}复制代码