Spring Boot 自动配置原理 有图有动画还看不明白吗

为了方便测试,自定义了一个SprongBootStarter

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.sgg.aopcache.cache.conf.RedissonAotoConfiguration

image-202203172****4599

1.@SpringBootApplication 核心注解

注解的元信息

@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) })

看这个注解 @EnableAutoConfiguration 看名字就知道 开启自动配置

好,点进去这个注解

2. @EnableAutoConfiguration 开启自动配置注解

首先看下这个注解的元信息和属性

@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 {};

}

exclude() excludeName() 如果需要排除某些自动配置类 可以给这两个参数设置值

最重要的看这个注解

3.@Import(AutoConfigurationImportSelector.class)

@Import注解将某个组件导入spring容器中

我们看下 AutoConfigurationImportSelector 这个类都干了什么事情

找到这个方法 selectImports

image-202203172****1914

调用了getAutoConfigurationEntry 方法

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

image-202203172****7646

image-202203172****6792

getBeanClassLoader()

可以看到这个方法的第二个参数获取了类加载器 想想我们自定义starter 的META-INF 文件夹是放在哪里的?

放在resource目录下,这个目录的路径由谁加载,由 AppClassLoader负责加载

image-202203172****7261

点进loadFactoryNames 方法

4. SpringFactoriesLoader.loadFactoryNames

image-202203172****6193

获取了 @EnableAutoConfiguration 注解的全限定类名

image-202203172****2045

image-202203172****5077

首先执行这个方法 loadSpringFactories(classLoader) 注意把类加载器传进去了

这个方法返回一个 Map<String, List<string>> </string>

然后再调用它的 .getOrDefault(factoryTypeName, Collections.emptyList()) 方法 也就是获取key = factoryTypeName 的value

而value 是一个String类型的集合 也就是自动配置类的全限定类名

我们跟进这个方法看一下

5.loadSpringFactories(classLoader)

image-202203172****2929

image-202203172****9973

重点看这个else代码块都做了什么事

 Enumeration<URL> 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;

image-202203172****6956

image-202203172****2699

如果是我们自定义的 spring.factories 配置文件,我们一般只会写 org.springframework.boot.autoconfigure.EnableAutoConfiguration= xxxx

而springboot官方的starter不单单只有

org.springframework.boot.autoconfigure.EnableAutoConfiguration

image-202203172****1134

所以在这我们打断点多循环几次

idea64_Cyg5Ar5RcZ

image-202203172****8838

image-202203172****1615

最后可以看到 我们自定义starter 的 spring.factories文件信息已经被放到了 LinkedMultiValueMap result 中 并返回

返回前还将数据都放到了缓存中

image-202203172****1396

至此,候选的自动配置类全限定类名都已经拿到了,之后还要经历筛选和过滤

image-202203172****7997

最终返回经过了排除和过滤的自动配置类的全限定名数组

#Java开发##Spring##学习路径#
全部评论

相关推荐

1 10 评论
分享
牛客网
牛客企业服务