SpringBoot源码之SpringApplication.run启动流程

本文详细剖析了SpringBoot的启动过程,从创建SpringApplicationRunListeners开始,到Environment准备,Banner打印,再到ApplicationContext的创建和刷新,包括配置初始化、Bean定义注册、事件发布等步骤,深入理解SpringBoot的运行机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

  • SpringApplication初始化

         

设置初始化器列表:多个classpath*:META-INF/spring.factories中的属性KEY为                        org.springframework.context.ApplicationContextInitializer的属性的值。

               

         设置监听器列表:多个classpath*:META-INF/spring.factories中的属性KEY为                        org.springframework.context.ApplicationListener的属性的值。

                

  • 调用SpringApplication的run方法

1.创建SpringApplicationRunListeners,并调用starting()

2.准备Environment

  • 获取或创建Environment,WEB项目返回StandardServletEnvironment
  • 配置Environment
  • 发布ApplicationEnvironmentPreparedEvent事件

3.打印Banner

4创建应用上下文AnnotationConfigEmbeddedWebApplicationContext

AnnotationConfigEmbeddedWebApplicationContext:

接受注解类作为输入-特别是@Configuration,@Component和依从JSR-330使用 {@code javax.inject}注解的类。允许逐个注册类(指定类名作为配置位置)以及类路径扫描(指定基本包作为配置位置)。对于多个{@code@Configuration}类,后面的{@code@Bean}定义将覆盖先前加载文件中定义的定义。可以通过额外配置类来有意的覆盖某些bean定义。

Em

<think>好的,我需要帮助用户解决在使用spring-jcl时出现的NoSuchMethodError错误,特别是与commons-logging相关的问题。用户还提到了SpringFactoriesLoader、从类路径中移除依赖以及冲突解决,我需要综合这些信息给出解决方案。 首先,回顾用户提供的引用内容。引用[3]提到spring-jcl-5.1.2.RELEASE.jar在启动时检测日志实现,这可能导致与旧版commons-logging冲突。用户的问题可能是由于项目中同时存在spring-jcl和commons-logging,导致类加载器加载了错误的类,从而引发NoSuchMethodError。例如,如果某个库依赖旧版commons-logging,而spring-jcl已经提供了新的实现,就可能出现方法不匹配的情况。 接下来,我需要确定常见的解决步骤。首先检查依赖树,使用Maven的mvn dependency:tree命令找出冲突的依赖,特别是commons-logging的存在。然后排除不需要的依赖,比如在Maven中添加exclusion标签。用户提到remove-from-classpath,所以需要确保commons-logging被正确排除。另外,可能需要统一版本号,比如确保所有模块使用相同版本的Spring Framework,避免不同模块引入不同版本的日志库。 另外,用户提到SpringFactoriesLoader,这可能涉及到Spring Boot的自动配置机制。如果存在多个日志实现的配置,可能需要检查spring.factories文件是否有重复或冲突的条目。但这个问题可能较少见,主要关注依赖冲突更实际。 还有引用[1]中的mvn dependency:resolve命令可以用来下载依赖的源码,可能帮助调试,但用户的问题更可能在于依赖冲突。引用[2]中的例子显示添加特定版本的依赖解决了兼容问题,类似地,可能需要强制指定某个版本的commons-logging或spring-jcl。 可能的解决方案步骤: 1. 生成依赖树,找出是否有commons-logging被引入。 2. 排除所有传递依赖中的commons-logging。 3. 检查Spring版本是否一致,避免不同模块引入不同版本的spring-jcl。 4. 确保类路径中只有spring-jcl而没有commons-logging。 5. 如果问题依旧,可能需要手动添加适配层或排除其他冲突的依赖。 此外,用户提到的NoSuchMethodError可能在运行时发生,说明编译时没问题,但运行时加载了不兼容的类。例如,PooledByteBufAllocator的构造方法在某个版本中被修改,导致旧代码调用不存在的方法。类似地,commons-logging中的某个类可能在spring-jcl中被修改或替换,导致方法签名不一致。 需要提醒用户注意依赖管理,特别是在使用Spring Boot时,其starter通常会管理依赖版本,但手动添加依赖可能覆盖这些版本。因此,检查所有显式引入的依赖是否有版本冲突,并利用Maven的dependencyManagement统一版本。 总结,解决方案应围绕依赖排除、版本统一和类路径检查展开,确保没有旧的commons-logging库存在。</think>### 解决 `spring-jcl` 与 `commons-logging` 冲突导致的 `NoSuchMethodError` 问题 #### 问题原因分析 1. **依赖冲突**:`spring-jcl` 是 Spring Framework 5 中用于替代 `commons-logging` 的日志门面实现[^3]。若项目中同时存在 `spring-jcl` 和旧版 `commons-logging`,类加载器可能加载了错误的日志实现类,导致方法签名不匹配。 2. **版本不兼容**:不同模块可能依赖不同版本的日志库(如 Spring Boot 模块与第三方库),导致 `SpringFactoriesLoader` 加载工厂类时出现冲突。 3. **类路径残留**:未彻底排除 `commons-logging`,Maven/Gradle 的依赖传递可能重新引入该库。 --- #### 分步解决方案 ##### 1. **检查依赖树并排除冲突** 通过 Maven 生成依赖树,定位 `commons-logging` 的来源: ```bash mvn dependency:tree -Dincludes=commons-logging ``` 在 `pom.xml` 中排除所有传递依赖的 `commons-logging`: ```xml <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> ``` ##### 2. **强制统一日志库版本** 在 Maven 的 `<dependencyManagement>` 中显式指定 `spring-jcl` 版本: ```xml <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jcl</artifactId> <version>5.3.18</version> <!-- 与 Spring Boot 版本对齐 --> </dependency> </dependencies> </dependencyManagement> ``` ##### 3. **验证类路径** 确保编译后的 `WEB-INF/lib` 或 `BOOT-INF/lib` 中无 `commons-logging-*.jar`。可通过以下命令检查: ```bash mvn clean package && unzip -l target/*.jar | grep commons-logging ``` ##### 4. **适配 SpringFactoriesLoader** 若冲突由 `spring.factories` 中多个日志适配器引起,在 `src/main/resources/META-INF` 下添加 `spring.factories` 文件,显式指定日志门面: ```properties org.springframework.boot.logging.LoggingSystemFactory=\ org.springframework.boot.logging.logback.LogbackLoggingSystemFactory ``` ##### 5. **使用 Maven 插件解决冲突** 通过 `maven-enforcer-plugin` 禁止引入 `commons-logging`: ```xml <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <executions> <execution> <id>no-commons-logging</id> <goals> <goal>enforce</goal> </goals> <configuration> <rules> <bannedDependencies> <excludes> <exclude>commons-logging:*</exclude> </excludes> </bannedDependencies> </rules> </configuration> </execution> </executions> </plugin> ``` --- #### 验证方案 1. **运行时检查**:添加 JVM 参数 `-verbose:class`,观察日志中是否加载了 `spring-jcl` 相关类: ```bash java -verbose:class -jar your-app.jar | grep 'LogAdapter' ``` 预期输出应包含 `org.springframework.boot.logging.LogAdapter`,而非 `org.apache.commons.logging.Log`。 2. **单元测试**:编写测试用例验证日志输出是否正常: ```java @SpringBootTest public class LoggingTest { private static final Logger logger = LoggerFactory.getLogger(LoggingTest.class); @Test public void testLogOutput() { logger.info("Test log message"); // 验证日志是否通过 SLF4J/Logback 输出 } } ``` --- #### 引用说明 - [^1]: 使用 `mvn dependency:resolve` 可辅助下载源码调试依赖问题。 - [^3]: `spring-jcl` 在启动时动态适配日志实现,需确保无冲突的旧版库干扰。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值