Springboot-自动配置 AutoConfigure

本文以新建Spring Boot项目为例,剖析其自动配置原理。通过分析@SpringBootApplication注解,重点探讨@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)的作用。指出自动配置包路径默认从启动类所在包开始,还介绍了如何加载spring.factories配置文件下的类,以及自动配置类生效与业务场景的关系。

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

1.引入案例

1.1 新建一个Springboot项目

新建时,勾选了spring-web组件依赖,创建了一个TestController,配置文件完全是空的,直接跑起来:
项目结构图
浏览器访问http://localhost:8080/test 看看结果
访问结果
看到这里,对springboot不熟悉的小伙伴就会有疑问了(大神请忽略),springboot启动的时候,到底帮我们加载了一些什么配置,别忘了,我们在创建项目的时候在pom文件添加了spring-boot-starter-web组件,点击组件进去可以看到具体的依赖项(太多了,就不贴出来了,有tomcat、webMvc的等等),

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

那么Springboot到底是如何加载我们添加的组件依赖默认组件场景的,这个需要回看我们的主启动类头上有个注解:@SpringBootApplication,点开注解进去看,发现它是个组合注解:

@Target(ElementType.TYPE) //注解的作用域
@Retention(RetentionPolicy.RUNTIME) //注解的生存周期
@Documented //可以被文档化
@Inherited //注解用于标注一个父类的注解是否可以被子类继承
@SpringBootConfiguration //声明为一个配置类 proxyBeanMethods是否开启bean代理,默认是true,从IOC容器中取;如果是false则每次获取都是一个新的实例
@EnableAutoConfiguration //开启自动配置---这个将是我们研究的重点
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) //包扫描的规则

经过分析,开启自动配置的注解是 @EnableAutoConfiguration,点开注解进去看到又是一个组合注解,我们开始分析@Target,@Retention,@Documented,@Inherited这几个上面分析了,不是重点我们忽略掉,关注点放在:@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class);

/** @author Phillip Webb
 * @author Stephane Nicoll
 * @since 1.0.0
 * @see ConditionalOnBean
 * @see ConditionalOnMissingBean
 * @see ConditionalOnClass
 * @see AutoConfigureAfter
 * @see SpringBootApplication
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
1.2 分析 @AutoConfigurationPackage

这个类的注释上面写着是“注册packages”,我们看到

/**
 * Registers packages with {@link AutoConfigurationPackages}. When no {@link #basePackages
 * base packages} or {@link #basePackageClasses base package classes} are specified, the
 * package of the annotated class is registered.
 *
 * @author Phillip Webb
 * @since 1.3.0
 * @see AutoConfigurationPackages
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

@Import(AutoConfigurationPackages.Registrar.class),点进去,断点打上,看它做了什么,
在这里插入图片描述
step into 到方法PackageImports上,拿到了启动类BootTestApplication所在的包路径,然后注册到容器中
正是因为有这个注解,我们上面的TestController是在这个com.wxq.csdn包路径下的,默认就能识别到,那其它路径能不能识别呢?

在这里插入图片描述在这里插入图片描述
针对上面的疑问,我们来做一个测试,在主启动类外边再新建一个包,然后写一个TestController01,看看能不能访问到,这里给出结论是访问不到(如下面的两张图),因为Springboot自动配置包路径的时候默认是从启动类所在的包找的,其它路径它是不认识的;那有没有办法让springboot认识这个包路径,办法是有的,不然读源码干嘛,请继续往下看
在这里插入图片描述
在这里插入图片描述
针对上面问题,解决com.wxq.csdn01这个包不识别的问题,
在启动类似@ComponentScan(value = “com.wxq.csdn01”),告诉springboot启动的时候来扫描一下这个包下的类,注册和加载进容器,重启项目,访问刚刚404的地址,结果如下:
在这里插入图片描述

在这里插入图片描述

1.3 分析@Import(AutoConfigurationImportSelector.class)

1.1 先抛出结论:读取所有META-INF/spring.factories配置文件下写死的路径的类加载到容器中,主要是这个spring-boot-autoconfigure包下的spring.factories配置的类;
在这里插入图片描述
1.2 看看springboot是怎么找到spring.factories文件的
通过断点调试发现,主启动类的run方法实现里面调用了refreshContext(context);,这个会调用到AutoConfigurationImportSelector里面的 process方法,下面我们一步一步断点进去看,
先进来主启动类的run方法
在这里插入图片描述
F9继续走下去(因为我提前打好断点了,第一次调试的朋友请用F7 一步一步调进去),方法执行到上面说的process里面,注意一个getAutoConfigurationEntry,
在这里插入图片描述
继续走进去看到这句:List configurations = getCandidateConfigurations(annotationMetadata, attributes); 继续往下走看到这个方法,解析出来的configurations正好是我们上面说的spring.factories配置的Auto Configure
在这里插入图片描述
那么到这里,我们已经知道了springboot如何自动加载配置类,但是加载了不一定就生效的,我们拿下面的例子说明
打开spring-boot-autoconfigure包下的源码,看到的都是springboot默认帮我们准备好的配置场景(图没截取到全部)
在这里插入图片描述
我们拿jdbc这个举例,因为这个大家应该很熟悉,如图,打开DataSourceAutoConfiguration发现有报错,因为我们根本没有引入Jdbc相关的依赖,所以这个配置类是不生效的,@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) 这个条件不满足
在这里插入图片描述
我们拿一个生效的配置类举例,因为我们引入了spring-boot-starter-web组件,那么web场景的配置是生效的,我们依旧是看源码,web目录下的配置类,
在这里插入图片描述
点开 DispatcherServletAutoConfiguration这个自动配置类,把DispatcherServlet注册到容器中,这个是springMvc的核心,
在这里插入图片描述

总结

1.自动配置原理,关键在于2个注解**@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)**,上面写的看起来可能不太好懂,但是动手跟着上面的步骤去调试,相信应该能看懂。
2.自动配置类是否生效,需要看我们pom文件里面有没有使用到具体的业务场景,比如上面的案例,我们没有使用到jdbc相关的场景,它的配置类是不生效的。

<think>我们正在分析三个jar包之间的兼容性关系:spring-beans-5.3.39.jar,spring-boot-autoconfigure-2.5.9.jar和spring-boot-autoconfigure-2.6.15.jar。重点在于它们可能导致`NoSuchMethodException`的问题。##1.版本兼容性背景SpringBoot自动配置模块(spring-boot-autoconfigure)依赖于SpringFramework的核心模块(如spring-beans)。SpringBoot每个版本都明确指定了与之兼容的SpringFramework版本。-**spring-boot-autoconfigure-2.5.9**:属于SpringBoot2.5.x系列,要求SpringFramework版本为5.3.x。-**spring-boot-autoconfigure-2.6.15**:属于SpringBoot2.6.x系列,要求SpringFramework版本为5.3.x(但通常要求5.3.x的较高版本,且可能包含一些不向后兼容的改动)。-**spring-beans-5.3.39**:属于SpringFramework5.3.x系列,是5.3.x的较新版本。##2.兼容性分析###2.1SpringBoot2.5.x与SpringFramework5.3.xSpringBoot2.5.x明确设计为与SpringFramework5.3.x兼容。spring-beans-5.3.39.jar应该与spring-boot-autoconfigure-2.5.9.jar完全兼容。###2.2SpringBoot2.6.x与SpringFramework5.3.xSpringBoot2.6.x同样基于SpringFramework5.3.x,但需要注意的是:-SpringBoot2.6.x可能会使用SpringFramework5.3.x中新增的方法(这些方法在SpringFramework5.3的早期版本中不存在)。-spring-beans-5.3.39.jar是5.3.x的较新版本,因此它应该包含5.3.x系列的所有方法。所以,理论上spring-boot-autoconfigure-2.6.15.jar也应该与spring-beans-5.3.39.jar兼容。###2.3潜在问题:NoSuchMethodException如果出现`NoSuchMethodException`,通常是因为:1.**编译时使用的类版本与运行时加载的类版本不一致**:例如,在编译时使用了包含某个方法的类(高版本),而运行时加载的类(低版本)中不存在该方法。2.**依赖传递导致版本冲突**:项目中可能存在多个版本的spring-beans,而类加载器加载到了旧版本的spring-beans。####具体场景分析假设我们有一个项目,其依赖如下:-直接依赖:spring-boot-autoconfigure-2.6.15.jar(需要SpringFramework5.3.18+)-但传递依赖或手动引入了spring-beans-5.3.16.jar(较旧的5.3.x版本)此时,如果SpringBoot2.6.15的自动配置代码调用了SpringFramework5.3.18中才新增的方法,而运行时的spring-beans版本是5.3.16,就会抛出`NoSuchMethodError`(注意:`NoSuchMethodException`通常出现在反射调用时,但根本原因类似)。##3.解决方案###3.1确保版本一致使用SpringBoot提供的依赖管理(BOM)来统一版本。在Maven中,通过`spring-boot-starter-parent`或`spring-boot-dependencies`来管理依赖版本。例如,对于SpringBoot2.6.15,在pom.xml中配置:```xml<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.15</version></parent>```这样,所有SpringFramework相关的依赖(包括spring-beans)都会被自动设置为与SpringBoot2.6.15兼容的版本(即5.3.39或更高)。###3.2检查依赖冲突使用Maven或Gradle的依赖树分析工具,检查是否存在低版本的spring-beans被引入。-**Maven**:```bashmvndependency:tree-Dincludes=org.springframework:spring-beans```查看输出,确保spring-beans的版本是5.3.39(或SpringBoot2.6.15要求的版本)。-**Gradle**:```bashgradledependencies--configurationruntimeClasspath|grepspring-beans```###3.3排除旧版本如果发现其他依赖引入了旧版本的spring-beans,需要排除掉:```xml<dependency><groupId>some.group</groupId><artifactId>some-artifact</artifactId><exclusions><exclusion><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId></exclusion></exclusions></dependency>```###3.4升级SpringBoot版本如果项目使用的是SpringBoot2.5.9,但希望使用spring-beans-5.3.39,这通常是安全的,因为5.3.39是5.3.x的补丁版本。但若项目使用的是SpringBoot2.6.15,则必须使用SpringFramework5.3.18及以上版本,而5.3.39符合要求。##4.典型错误示例###场景:升级SpringBoot后出现NoSuchMethodError**错误日志**:```java.lang.NoSuchMethodError:org.springframework.beans.factory.support.DefaultListableBeanFactory.setDependencyComparator(Ljava/util/Comparator;)V```**原因**:SpringBoot2.6.x调用了`DefaultListableBeanFactory`中新增的方法,但运行时加载的是旧版本的spring-beans(如5.2.x或5.3.16)。**解决**:强制使用spring-beans-5.3.39。##5.总结|SpringBootAutoconfigure版本|要求SpringBeans版本|是否兼容spring-beans-5.3.39||-------------------------------|------------------------|-----------------------------||2.5.9|5.3.x(推荐5.3.16+)|是||2.6.15|5.3.18+|是(5.3.39满足要求)|只要保证spring-beans的版本不低于SpringBoot要求的最低版本,就不会出现`NoSuchMethodException`或`NoSuchMethodError`。§§相关问题§§1.如何解决SpringBoot升级后出现的`NoSuchMethodError`?2.Maven如何排除传递依赖中的冲突版本?3.SpringBoot2.5.x和2.6.x在自动配置方面有哪些重大变更?</think>### Spring Jar 兼容性分析与 NoSuchMethodException 解决方案 #### 1. **版本兼容性分析** | JAR 文件 | Spring Boot 兼容范围 | Spring Framework 要求 | 主要风险点 | |-----------------------------------|--------------------------|------------------------|--------------------------------| | `spring-beans-5.3.39.jar` | Boot 2.4.x - 2.7.x | Framework 5.3.x | 核心功能基础,需匹配Boot版本 | | `spring-boot-autoconfigure-2.5.9.jar` | Boot 2.5.9 专用 | Framework 5.3.9+ | 使用旧版API,可能缺少新方法 | | `spring-boot-autoconfigure-2.6.15.jar` | Boot 2.6.15 专用 | Framework 5.3.18+ | 依赖新API(如BeanFactory方法) | **关键结论**: 1. **跨版本组合风险**: - ✅ `spring-beans-5.3.39` + `autoconfigure-2.5.9`:完全兼容(同属5.3.x线) - ⚠️ `spring-beans-5.3.39` + `autoconfigure-2.6.15`:**高风险不兼容** - Boot 2.6.15 需要 Spring Framework 5.3.18+ 的新方法 - 5.3.39 > 5.3.18,但需验证具体API兼容性 - ❌ `autoconfigure-2.5.9` + `autoconfigure-2.6.15`:绝对冲突 2. **NoSuchMethodException 根源**: ```java // Boot 2.6.15 可能新增的方法(示例) public class ConfigurationClassParser { // 2.6.15新增方法(5.3.18+) public void newMethod() { ... } } // 使用5.3.39时若缺失此方法则报错 ``` #### 2. **典型问题场景与解决方案** ##### 场景1:Boot 2.6.x 使用旧版 Spring Beans **错误表现**: ``` Caused by: java.lang.NoSuchMethodError: org.springframework.beans.factory.support.DefaultListableBeanFactory.setDependencyComparator(Ljava/util/Comparator;)V ``` **解决方案**: 1. **版本对齐**(推荐): ```xml <!-- 保证Boot与Framework版本匹配 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.15</version> </parent> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <!-- 版本由Boot父POM自动管理 --> </dependency> ``` 2. **依赖排除 + 显式声明**: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.3.39</version> <!-- 显式指定高版本 --> </dependency> ``` ##### 场景2:混合使用不同Boot版本组件 **错误案例**: ```xml <!-- 错误组合 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>2.6.15</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.0</version> <!-- 内部依赖Boot 2.5.x组件 --> </dependency> ``` **解决方案**: 1. **统一Boot版本**: ```xml <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.6.15</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> ``` 2. **排除冲突依赖**: ```xml <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.0</version> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </exclusion> </exclusions> </dependency> ``` #### 3. **兼容性验证工具** 1. **Maven 依赖分析**: ```bash mvn dependency:tree -Dincludes=org.springframework:spring-beans,org.springframework.boot:spring-boot-autoconfigure ``` 输出示例: ``` [INFO] org.example:demo:jar:1.0 [INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.6.15:compile [INFO] | \- org.springframework.boot:spring-boot-autoconfigure:jar:2.6.15:compile [INFO] \- org.springframework:spring-beans:jar:5.3.39:compile <!-- 验证版本 --> ``` 2. **运行时验证代码**: ```java public class CompatibilityChecker { public static void main(String[] args) { checkMethodExist( "org.springframework.beans.factory.support.DefaultListableBeanFactory", "setDependencyComparator", Comparator.class ); } private static void checkMethodExist(String className, String method, Class<?>... params) { try { Class<?> clazz = Class.forName(className); clazz.getMethod(method, params); System.out.println("✅ 方法存在: " + method); } catch (Exception e) { throw new RuntimeException("❌ 缺失关键方法: " + method, e); } } } ``` #### 4. **最佳实践建议** 1. **版本管理原则**: - 始终使用 `spring-boot-starter-parent` 管理主版本 - 第三方依赖选择明确支持当前Boot版本的组件(如MyBatis Plus 3.5.0+支持Boot 2.6.x) 2. **升级路径**: ```mermaid graph LR A[Boot 2.5.9] -->|先升级| B[Framework 5.3.39] B --> C[Boot 2.6.15] C --> D[验证自动配置兼容性] ``` 3. **疑难问题定位**: - 使用 `-verbose:class` 启动参数查看类加载顺序 - 通过 `javap -c 类名` 反编译验证方法签名 > **关键提示**:Spring Boot 2.6.x 开始要求更高版本的 Spring Framework,混合使用 `autoconfigure-2.5.9` 和 `autoconfigure-2.6.15` **必然导致兼容性问题**[^2]。建议统一升级到 Boot 2.6.15 + Spring 5.3.39 组合。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值