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##学习路径#
全部评论

相关推荐

我对信贷业务其实不是特别感兴趣(当然也有价值,能把钱借给真正需要的人),但是对交易反欺诈这条线真的很感兴趣,觉得真的超级有意义。反欺诈产品是我们组支撑的产品线之一,看到和北京警企合作的推文,觉得报国有门,无比激动,我们未来的每一行代码,都能改变世界,帮助弱者不再受骗。还记得当时面试的时候,HR说我超过了很大部分二本学生的思维(后来知道我是我们组唯一的二本生),问我是如何做到的。我说因为16岁时候的梦想,我要做国家需要的工程师,后来发现自己不擅长物理,做不了芯片,但是一直希望自己能够做对社会真正有意义的产品。也记得第一次熟悉组里业务的时候,看到组里有一个产品叫交易反欺诈,当时仿佛触电一样,这简直是我接触到的最有意义的产品,下定决心以后一定要做这条产品线。我为警方办事,那我也是网络警察,我就可以改变这个世界(手动狗头)。也许没有人会知道我们的名字,但是我想大家一定能够感受到,是因为我们这些人的存在,生活才会有更多美好。当然,改变世界这个美好愿望,可能等我正式入职后会被工作毒打,可能上班就只想着下班,但人生总该有点期待,希望半年后再看自己这条动态,能欣慰的笑出来。我的原生家庭不怎么幸福,一路单打独斗到现在,我渴望靠工作改变命运,过上比父辈更好的生活,也更渴望自己成为自己幼年心目中那个了不起的英雄,为世界做出微小且美好的改变。
真烦好烦真烦:厉害,虽然现实很残酷,但是能在内心有自己的一份坚守真是太厉害了
牛客创作赏金赛
点赞 评论 收藏
分享
距离第一次面试刚刚好过去一个月,总算是oc了,后面也不打算再找了,所以简单做个总结bg双九科班简历牛客论坛+黑马点评,有个挑战杯大模型相关比赛决赛一等奖无实习经历,LeetCode除hot100之外有额外刷一些,大概200左右,八股一般,主要背了redis相关大概4月初开始投,虽然bg让我有不少面试机会,但大多都是一面挂,只有阿里智能信息顺利oc,鹅的复活赛进了一次二面。总结失败经验:没有实习经验、项目烂大街加上最开始确实没有完全吃透,基本一深入问就g以下记录一下时间线:美团&nbsp;4.23&nbsp;一面挂阿里国际&nbsp;4.29&nbsp;一面挂腾讯&nbsp;5.8&nbsp;一面挂阿里云&nbsp;5.9&nbsp;一面挂腾讯复活赛一番战&nbsp;5.13&nbsp;一面&nbsp;5.20二面挂淘天&nbsp;5.14&nbsp;一面挂(阿里妈妈的压迫感太强了)腾讯音乐&nbsp;5.14&nbsp;一面挂阿里智能信息&nbsp;5.15一面&nbsp;5.20二面&nbsp;5.23HR面&nbsp;HR面后三小时oc其实还投了不少,饿了么笔试没后续,蚂蚁笔试没后续,OPPO笔试挂,虾皮笔试挂,阿里控股、京东还在池子里,很早就投的顺丰发了个面试时间意向邮件后无后续以下是面经:美团、阿里国际、阿里智能信息已单独发腾讯一面:讲讲session和cookie,了不了解单点登录csrf攻击布隆过滤器讲讲cas讲讲redis里的数据结构,跳表有了解吗热帖排行功能展开讲讲讲讲你项目里的分布式锁acid、隔离级别,mysql默认是哪个级别,为什么ioc和aop手撕:连续子数组的最大和其实这次面试体验还挺好,就是单点登录问题面试官前面暗示了很多次,最后直截了当问了,但我这块当时确实没准备到淘天一面:除了maven还有什么管理第三方包;如何处理maven依赖冲突AC自动机了解吗布隆过滤器threadlocal,如何跨线程传递值mysql的锁了解吗,什么情况下会产生死锁商品数量多时如何考虑分库分表redisson自动续锁怎么解决死锁问题get和post的区别;为什么get中带url是不安全的循环依赖是什么,spring中如何解决,适用于什么情况ioc、aop讲讲为什么要做这两个项目csrf手撕快排,讲原理被拷打最狠的一集,阿里妈妈不愧是阿里妈妈,是我完全高攀不起了腾讯复活赛一番战一面:static的作用final和finally的区别==和equals的区别为什么有了equals还需要hashcode为什么重写&nbsp;equals()&nbsp;时必须重写&nbsp;hashCode()&nbsp;方法?ioc和aopredis有哪些部署架构讲讲redisson对分布式锁的优化,什么情况下只使用单体redis手撕:删除有序链表中的重复值都是很基础的八股
点赞 评论 收藏
分享
评论
2
9
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务