Springboot启动流程源码分析
Springboot启动流程源码分析(一)(自动配置)
我们首先从pom.xml文件开始分析
- 其中它主要是依赖一个父项目,主要是管理控制项目的资源过滤及插件依赖!
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent>
- 在父启动类里,发现还有一个父依赖
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.3.2.RELEASE</version> </parent>
- 这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;
- 以后我们导入依赖默认是不需要写版本
- 但是如果导入的包没有在依赖中管理着就需要手动配置版本了
启动器 spring-boot-starter介绍
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
- springboot-boot-starter-xxx:就是spring-boot的场景启动器
- spring-boot-starter-web:帮我们导入了web模块正常运行所依赖的组件
- SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来
- 我们要用什么功能就导入什么样的场景启动器即可 ;我们未来也可以自己自定义 starter;
主启动类SpringbootApplication---->一系列注解原理
1、SpringbootApplication主启动类main方法
- 默认的主启动类,一个简单的启动类并不简单!下面我们来分析一下 @SpringBootApplication 注解都干了什么
@SpringBootApplication // 来标注一个主程序类 说明这是一个Spring Boot应用 public class SpringbootApplication { public static void main(String[] args) { //以为是启动了一个方法,没想到启动了一个服务 SpringApplication.run(SpringbootApplication.class, args); } }
2、@SpringBootApplication注解
-
来标注一个主程序类 说明这是一个Spring Boot应用
-
SpringBoot就应该运行这个类的main方法来启动SpringBoot应用
-
在这个注解中还有许多其他的注解,如下代码所示
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { // ... }
3、@ComponentScan注解(@SpringBootApplication子注解)
-
该注解在Spring中很重要 ,它对应XML配置中的元素。
-
作用:自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器中
4、@SpringBootConfiguration注解(@SpringBootApplication子注解)
- 作用:SpringBoot的配置类 ,标注在某个类上 , 表示这是一个SpringBoot的配置类
- 在该注解下含有两个注解:@Configuration、@Component
@Configuration public @interface SpringBootConfiguration {} // @Configuration点进去得到下面的 @Component @Component public @interface Configuration {}
-
这里的 @Configuration,说明这是一个配置类 ,配置类就是对应Spring的xml 配置文件
-
这里的 @Component 这就说明,启动类本身也是Spring中的一个组件而已,负责启动应用!
我们回到 SpringBootApplication 注解中继续看。
5、@EnableAutoConfiguration(@SpringBootApplication的注解)
-
注解作用:开启自动配置功能
- 以前我们需要自己配置的东西,而现在SpringBoot可以自动帮我们配置
- @EnableAutoConfiguration告诉SpringBoot开启自动配置功能,这样自动配置才能生效
-
点进EnableAutoConfiguration注解继续查看:
-
@AutoConfigurationPackage :自动配置包
@Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage { } -
@import :Spring底层注解@import , 给容器中导入一个组件
- Registrar.class 的作用:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器
-
-
退到上一步,继续看@EnableAutoConfiguration的注解
-
**@Import({AutoConfigurationImportSelector.class}) :给容器导入组件 **
- AutoConfigurationImportSelector :自动配置导入选择器,那么它会导入哪些组件的选择器呢?我们点击去这个类看源码:
- getCandidateConfigurations方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { // 这里的getSpringFactoriesLoaderFactoryClass()方法,返回的就是注解类Class:EnableAutoConfiguration List<String> configurations = SpringFactoriesLoader. loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader()); return configurations; } // 返回自动配置类EnableAutoConfiguration protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; }
- 这个方法又调用了 SpringFactoriesLoader 类的静态方法loadFactoryNames() 方法
// @Nullable ClassLoader classLoader 参数为该类自己SpringFactoriesLoader public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { // 就是传过来的EnableAutoConfiguration.class; String factoryTypeName = factoryType.getName(); // 这里又调用了loadSpringFactories方法,Map有键为EnableAutoConfiguration就返回,没有取空集合 return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); }
- 我们继续追踪查看 loadSpringFactories 方法
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) { // 获得classLoader,我们返回可以看到这里得到的就是EnableAutoConfiguration标注的类本身 MultiValueMap<String, String> result = cache.get(classLoader); // 缓存中若有,则直接返回 if (result != null) return result; try { // 去加载文件资源 "META-INF/spring.factories" Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); // 将读取到的资源遍历,封装成为一个Properties Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry<?, ?> entry : properties.entrySet()) { String factoryTypeName = ((String) entry.getKey()).trim(); for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { result.add(factoryTypeName, factoryImplementationName.trim()); } } } cache.put(classLoader, result); return result; } }
spring.factories文件
- 我们可以全局搜索并打开spring.factories , 看到了很多自动配置的信息
AopAutoConfiguration实例
- 随便找一个自动配置类打开看看,比如 :AopAutoConfiguration
@Configuration(proxyBeanMethods = false) @ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true) public class AopAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnClass(Advice.class) static class AspectJAutoProxyingConfiguration{ } @Configuration(proxyBeanMethods = false) @ConditionalOnMissingClass("org.aspectj.weaver.Advice") @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true) static class ClassProxyingConfiguration{ }
- 自动配置的实现是加载classpath下所有的META-INF/spring.factories配置文件
- 将其中对应的 org.springframework.boot.autoconfigure 包下的配置项
- 通过反射实例化将标注了 @Configuration的JavaConfig形式的聚集加载到IOC容器完成配置
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY