SpringBoot自动配置原理
SpringBoot项目无需各种配置文件,一个main方法,就能把项目启动起来。那么我们看看SpringBoot是如何进行自动配置和启动的。
先看下图的SpringBoot项目的启动类
SpringBoot程序能够实现自动配置主要来源于@SpringBootApplication这个复合注解,其中有三个注解是比较重要的:
1.@ComponentScan注解(扫描注解)
这个注解在Spring中很重要,它对应XML配置中的元素
作用:自动扫描包(扫描当前主启动类同级的包)并加载符合条件的组件或者bean,将这个bean定义加载到IOC容器中。
2.@SpringBootConfiguration注解
表明这是一个SpringBoot配置类,配置类就是对应Spring的xml配置文件
3.@EnableAutoConfiguration注解
开启自动配置功能,里面包含两个比较重要的注解@AutoConfigurationPackage和@Import。
@AutoConfigurationPackage:自动配置包
@Import : ( 自动注册包和@ComponentScan自动扫描包,是联动的)Spring底层注解@Import,给容器中导入一个组件。
Registrar.class 作用:将主启动类所在包及包下面所有子包里面的所有组件扫描到Spring容器
@Import(AutoConfigurationImportSelector.class): 给容器导入组件
此注解是自动装配的核心注解,其导入的AutoConfigurationImportSelector类中有个selectImports( )方法, 此方法中有一个 getAutoConfigurationEntry( )方法用于获取自动配置的实体,
getAutoConfigurationEntry( )方法中有一个 this.getCandidateConfigurations(annotationMetadata, attributes) 获得候选配置的方法
getCandidateConfigurations()这个方法又调用SpringFactoriesLoader 类的静态方法!
我们进入SpringFactoriesLoader类loadFactoryNames() 方法------->获取所有的加载配置。
然后继续点击查看 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 34 35 36 37 38 39 40 41 42 | private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) { Map<String, List<String>> result = (Map)cache.get(classLoader); if (result != null ) { return result; } else { HashMap result = new HashMap(); try { Enumeration urls = classLoader.getResources( "META-INF/spring.factories" ); 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[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); String[] var10 = factoryImplementationNames; int var11 = factoryImplementationNames.length; for ( int var12 = 0 ; var12 < var11; ++var12) { String factoryImplementationName = var10[var12]; ((List)result.computeIfAbsent(factoryTypeName, (key) -> { return new ArrayList(); })).add(factoryImplementationName.trim()); } } } result.replaceAll((factoryType, implementations) -> { return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)); }); cache.put(classLoader, result); return result; } catch (IOException var14) { throw new IllegalArgumentException( "Unable to load factories from location [META-INF/spring.factories]" , var14); } } } |
loadSpringFactories 方法中的classLoader.getResources(“META-INF/spring.factories”) —》获取项目资源;
spring-boot-autoconfigure jar 包下就有这样一个spring.factories文件。打开,如下图可以看到所有需要配置的类全路径都在文件中,每行一个配置,多个类名逗号分隔,而\表示忽略换行
可以看出 spring.factories 文件可以将项目包以外的 bean(即在 pom 文件中添加依赖中的 bean)注册到 spring 容器。由于@ComponentScan 注解只能扫描项目包内的 bean并注册到spring容器中,因此需要 @EnableAutoConfiguration 注解来注册项目包外的bean。而 spring.factories 文件,则是用来记录项目包外需要注册的bean类名。
思考:这么多自动配置为什么有的没有生效,需要导入对应的start才能有作用!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程