Spring Boot 3.0.x 自动配置文件加载原理

SpringBoot通过@EnableAutoConfiguration注解开启自动配置,该注解导入AutoConfigurationImportSelector,该选择器根据META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件加载自动配置类。自动配置类的加载涉及扫描主配置类所在包及其子包,以及动态选择导入配置类的过程。

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

我们知道 Spring Boot 开启自动配置使用的是 @EnableAutoConfiguration 注解,一般使用组合了它的 @SpringBootApplication 主注解即可。那么 Spring Boot 是如何加载包含了各种需要自动配置的类的配置文件的呢?本文我们基于 Spring Boot 3.0.6 一起看看 Spring Boot 自动配置文件加载的原理。

@EnableAutoConfiguration 注解的源码如下:

/**
 * 启用Spring应用程序上下文的自动配置,尝试猜测和配置您可能需要的bean。
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited // 允许子类继承
@AutoConfigurationPackage // 注解会将主配置类(@SpringBootApplication标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器
@Import(AutoConfigurationImportSelector.class) // 导入组件,将所有需要导入的组件以全类名的方式返回,这些组件就会被添加到容器中
public @interface EnableAutoConfiguration {

	/**
	 * 环境属性,可以用来覆盖自动配置是否启用。
	 */
	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * 用于排除某些自动配置类,被排出的自动配置类不会被加载到容器中。
	 */
	Class<?>[] exclude() default {};

	/**
	 * 根据类名排除自动配置类,被排除的自动配置类不会被加载到容器中。
	 */
	String[] excludeName() default {};
}

上面最关键的两个注解是:

  • @AutoConfigurationPackage:用于自动配置启用时扫描指定类所在的包及其子包中的所有类。该注解通常用于在应用程序入口类上使用,以便自动配置能够自动扫描应用程序所需的包。具体来说,该注解会将指定类所在的包及其子包中的所有类的所在包路径作为自动配置的 basePackage,然后将其注册到 Spring 的 BeanFactory 中,以便自动配置能够扫描这些包中的所有类。
  • @Import:导入配置类,这里导入的就是其中的 ImportSelector 接口实现。

自动配置 @Import 注解导入的是 AutoConfigurationlmportSelector.class 类,这也是这个注解的关键所在,它实现了 ImportSelector 接口。Spring Boot 中的 ImportSelector 接口是一个用于动态导入配置类的接口,它可以根据条件动态地选择需要导入的配置类。

在 Spring Boot 中,我们可以使用 @Import 注解来导入配置类,但是如果需要根据条件来动态选择导入哪些配置类,就需要使用 ImportSelector 接口。

ImportSelector 接口源码如下:

public interface ImportSelector {
    String[] selectImports(AnnotationMetadata importingClassMetadata);

    @Nullable
    default Predicate<String> getExclusionFilter() {
        return null;
    }
}

该接口包含了两个方法:

  • selectImports

    该方法是 ImportSelector 接口的的核心方法,用于从传入的 AnnotationMetadata 中选择要导入的配置类。在该方法中,可以根据 AnnotationMetadata importingClassMetadata 中的注解信息来决定需要导入哪些配置类。返回一个 String 数组,其中包含要导入的配置类的全限定类名。

  • getExclusionFilter

    该方法用于提供一个谓词函数,用于过滤掉一些不需要导入的配置类。该函数接受一个字符串参数(即要导入的配置类的全限定类名),并返回一个布尔值,指示该配置类是否需要被排除。如果不需要进行任何过滤,可以返回 null 或一个恒返回 false 的谓词函数。

然后我们回到 AutoConfigurationlmportSelector 类,它的作用是根据类路径下的 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中定义的自动配置类来动态导入配置类。

AutoConfigurationlmportSelector 类实现的 ImportSelector 接口的两个方法源码如下:

public String[] selectImports(AnnotationMetadata annotationMetadata) {
    // 检查是否启用自动配置
    if (!this.isEnabled(annotationMetadata)) {
        // 如果未启用,则返回空数组
        return NO_IMPORTS;
    } else {
        // 获取自动配置条目
        AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
        // 返回自动配置条目中的配置类的字符串数组
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
}

public Predicate<String> getExclusionFilter() {
    // 返回一个谓词函数,用于过滤应该排除的自动配置类
    return this::shouldExclude;
}

进入 getAutoConfigurationEntry 方法,该方法用于用于获取自动配置条目,方法源码如下:

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    // 检查是否启用自动配置
    if (!this.isEnabled(annotationMetadata)) {
        // 如果未启用,则返回空的自动配置条目
        return EMPTY_ENTRY;
    } else {
        // 获取所有候选的自动配置类
        AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
        List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
        // 去除重复的自动配置类
        configurations = this.removeDuplicates(configurations);
        // 获取需要排除的自动配置类
        Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
        // 检查需要排除的自动配置类是否存在于候选的自动配置类中
        this.checkExcludedClasses(configurations, exclusions);
        // 从候选的自动配置类中去除需要排除的自动配置类
        configurations.removeAll(exclusions);
        // 应用配置类过滤器,过滤无效的自动配置类
        configurations = this.getConfigurationClassFilter().filter(configurations);
        // 触发自动配置导入事件
        this.fireAutoConfigurationImportEvents(configurations, exclusions);
        // 构造自动配置条目并返回
        return new AutoConfigurationEntry(configurations, exclusions);
    }
}

我们将关注点聚集在 getCandidateConfigurations 方法,该方法用于获取候选的自动配置类。方法源码如下:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    // 从 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中加载所有自动配置类
    List<String> configurations = ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).getCandidates();
    // 检查自动配置类列表是否为空
    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
    // 返回自动配置类列表
    return configurations;
}

其中,ImportCandidates.load 方法是从指定的位置加载所有实现了指定接口的类,并返回一个 ImportCandidate 实例,用于访问加载的类。在这里,该方法用于加载所有实现了 AutoConfiguration 接口的类。this.getBeanClassLoader() 用于获取当前线程的上下文类加载器,用于加载类。如果自动配置类列表为空,则会抛出一个 IllegalStateException 异常,提示用户检查自动配置文件是否正确。

上面提到的 ImportCandidates 类是一个辅助类,用于加载所有实现了指定接口的候选类。它有一个 load 方法,用于加载所有实现了指定接口的类,并返回一个 ImportCandidates 实例。

方法源码如下:

public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
    // 检查注解类是否为空
    Assert.notNull(annotation, "'annotation' must not be null");
    // 获取要使用的类加载器
    ClassLoader classLoaderToUse = decideClassloader(classLoader);
    // 获取要加载的自动配置类列表所在的位置
    String location = String.format("META-INF/spring/%s.imports", annotation.getName());
    // 在类路径中查找指定位置的资源
    Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
    // 保存所有候选类的列表
    List<String> importCandidates = new ArrayList();
    // 遍历所有找到的资源
    while (urls.hasMoreElements()) {
        URL url = urls.nextElement();
        // 读取资源中的所有候选类,并添加到列表中
        importCandidates.addAll(readCandidateConfigurations(url));
    }
    // 返回一个包含所有候选类的 ImportCandidates 实例
    return new ImportCandidates(importCandidates);
}

从源码中我们可以看到,Spring Boot 3.0.x 的自动配置逻辑是加载 META-INF/spring/%s.imports 配置文件中的自动配置,这个 %s 是占位符,指 @AutoConfiguration 注解的类的全路径名称,如下图所示:

该配置文件内容如下:

org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration
...... Spring Boot 3.0.6 共注册了142个自动配置类

可以看到,编写格式确实简单了,一些应用级别的自动配置类已经全移到这个新配置文件中了。而老的自动配置文件 (spring.factories) 还保留了一些系统级别的组件,如各种初始化器、监听器等,这些初始化器和监听器都会在 Spring Boot 启动时完成自动配置。

<think>我们正在使用Spring Boot 3.x(例如3.4.7)来配置Nacos作为配置中心。根据引用[2]和[3]的信息,Spring Boot 3.x需要对应特定的Nacos客户端版本。引用[2]提到,对于nacos2.x版本,如果Spring Boot版本是3.0.x或3.1.x,需要添加`nacos-config-spring-boot-starter`的版本为0.3.0-RC。但是,我们使用的是Spring Boot 3.4.7,因此需要确认最新的适配版本。 实际上,Spring Cloud Alibaba 2023.0.x版本已经支持Spring Boot 3.x,并且提供了对Nacos配置中心的支持。因此,我们更推荐使用Spring Cloud Alibaba的官方依赖,而不是单独的`nacos-config-spring-boot-starter`。 但是,请注意引用[4]中提到了bootstrap配置文件的使用。在Spring Cloud 2020.x之后,默认不再启用bootstrap上下文,需要额外引入依赖才能使用。但在Spring Boot 3.x中,我们也可以不使用bootstrap,而是使用`application.yml`进行配置,或者通过其他方式加载配置。 步骤: 1. 添加依赖:使用Spring Cloud Alibaba的依赖管理,添加Nacos Config Starter。 2. 配置Nacos配置中心:在`application.yml`中配置Nacos配置中心的地址、命名空间、组等。 3. 启用配置刷新:如果需要动态刷新配置,可以使用`@RefreshScope`注解。 4. 编写配置类:使用`@Value`或`@ConfigurationProperties`来获取配置。 具体步骤: 步骤1:添加依赖 在pom.xml中添加Spring Cloud Alibaba Nacos Config依赖,注意版本选择。根据Spring Boot 3.4.7,我们选择Spring Cloud 2023.0.x和Spring Cloud Alibaba 2023.0.1.0。 在`<dependencies>`中添加: ```xml <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>2023.0.1.0</version> </dependency> ``` 同时,为了确保依赖版本一致,我们使用`<dependencyManagement>`来管理版本(如果之前没有添加): ```xml <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2023.0.1</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2023.0.1.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> ``` 步骤2:创建配置文件 由于我们需要在应用启动之前获取配置中心的配置,因此建议使用`bootstrap.yml`(或`bootstrap.properties`)来配置Nacos Config的相关信息。但是,从Spring Cloud 2020.0开始,默认不启用bootstrap上下文,需要引入以下依赖: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> <version>4.1.1</version> <!-- 版本与Spring Cloud 2023.0.1对应,实际版本号由spring-cloud-dependencies管理,这里可以不写版本号 --> </dependency> ``` 或者,我们也可以不使用bootstrap,而将配置放在`application.yml`中,但这样配置中心的配置加载顺序可能会晚于部分Bean的初始化。因此,推荐使用bootstrap方式。 在`src/main/resources`下创建`bootstrap.yml`,内容如下: ```yaml spring: application: name: nacos-config-demo # 应用名称,用于构成Nacos配置的Data ID cloud: nacos: config: server-addr: 127.0.0.1:8848 # Nacos配置中心地址 file-extension: yaml # 配置文件扩展名,默认为properties,这里设置为yaml namespace: public # 命名空间,默认为public group: DEFAULT_GROUP # 组,默认为DEFAULT_GROUP # 其他配置:如username, password等 ``` 注意:在Nacos中,配置文件的Data ID的完整格式为:`${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}`。如果没有激活的profile,则格式为`${spring.application.name}.${spring.cloud.nacos.config.file-extension}`。 步骤3:在Nacos控制台添加配置 登录Nacos控制台(http://localhost:8848/nacos),在配置管理->配置列表中添加配置: - Data ID: `nacos-config-demo.yaml`(如果应用名为`nacos-config-demo`,且没有指定profile,则使用这个名称;如果指定了profile,例如dev,则Data ID为`nacos-config-demo-dev.yaml`) - Group: `DEFAULT_GROUP` - 配置格式: YAML - 配置内容: 例如 ```yaml demo: key: value ``` 步骤4:在Spring Boot应用中使用配置 创建一个配置类,使用`@Value`或`@ConfigurationProperties`来注入配置。 例如,使用`@Value`: ```java @RestController @RefreshScope // 支持动态刷新 public class ConfigController { @Value("${demo.key:default}") private String value; @GetMapping("/getConfig") public String getConfig() { return value; } } ``` 或者使用`@ConfigurationProperties`: ```java @ConfigurationProperties(prefix = "demo") @Component @Data // Lombok注解,生成getter/setter public class DemoProperties { private String key; } ``` 步骤5:启用配置刷新 如果需要动态刷新配置,在需要刷新的Bean上添加`@RefreshScope`注解(如上面的Controller)。当配置在Nacos中修改后,应用会收到通知并更新配置(注意:使用`@ConfigurationProperties`的类默认支持刷新,不需要`@RefreshScope`,但需要是Spring管理的Bean)。 步骤6:启动应用并测试 启动应用,访问`/getConfig`应返回配置的值。在Nacos控制台修改配置,发布后,应用会动态更新配置。 注意事项: 1. 如果不想使用bootstrap.yml,可以在application.yml中配置,但需要确保配置中心的配置在应用启动早期加载。另外,也可以设置环境变量`spring.cloud.bootstrap.enabled=true`来启用bootstrap,但推荐使用添加`spring-cloud-starter-bootstrap`依赖的方式。 2. 关于命名空间:在Nacos中,不同的命名空间可以隔离配置。如果使用非public命名空间,需要指定namespace的ID(一串字符串,可以在Nacos控制台命名空间详情中查看)。 3. 关于组:如果配置不在默认组,需要指定组名。 4. 如果配置中心有多个配置,可以使用`spring.cloud.nacos.config.shared-configs`或`spring.cloud.nacos.config.extension-configs`来引入多个配置。 示例:在bootstrap.yml中引入多个共享配置: ```yaml spring: cloud: nacos: config: shared-configs: - data-id: common.yaml group: DEFAULT_GROUP refresh: true # 是否动态刷新 - data-id: datasource.yaml group: DEFAULT_GROUP refresh: true ``` 5. 关于版本:确保所有依赖版本兼容。Spring Boot 3.x需要Spring Cloud Alibaba 2023.0.x版本。 常见问题: - 配置未加载:检查Data ID、group、namespace是否匹配,检查Nacos服务器是否可访问。 - 动态刷新不生效:检查是否添加了`@RefreshScope`(对于`@Value`)或使用了`@ConfigurationProperties`(自动刷新),并确保配置已设置自动刷新(shared-configs中refresh设置为true)。 通过以上步骤,即可在Spring Boot 3.x中成功集成Nacos配置中心。 相关问题: 1. 如何在Spring Boot 3.x中同时使用Nacos作为注册中心和配置中心? 2. Nacos配置中心如何实现多环境配置(如dev, test, prod)? 3.Spring Cloud Alibaba中,如何配置Nacos配置中心的高可用? 4. Nacos配置中心与Spring Cloud Config相比有哪些优势?</think>### Spring Boot 3.x 配置 Nacos 作为配置中心的步骤 在 Spring Boot 3.x(如 3.4.7)中配置 Nacos 作为配置中心,需使用兼容的依赖版本和配置方式。以下是详细步骤: --- #### 步骤 1:添加依赖 在 `pom.xml` 中添加 **Spring Cloud Alibaba Nacos Config** 依赖(需兼容 Spring Boot 3.x): ```xml <dependencies> <!-- Nacos 配置中心 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>2023.0.1.0</version> <!-- 兼容 Spring Boot 3.x --> </dependency> <!-- 启用 bootstrap 配置加载 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> <version>4.1.1</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <!-- Spring Cloud 2023.0.x --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2023.0.1</version> <type>pom</type> <scope>import</scope> </dependency> <!-- Spring Cloud Alibaba --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2023.0.1.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> ``` > **关键说明** > - `spring-cloud-starter-bootstrap` 用于启用 bootstrap 配置加载(必须)[^4] > - 版本 `2023.0.1.0` 确保兼容 Spring Boot 3.x[^2][^3] --- #### 步骤 2:创建 bootstrap 配置文件 在 `src/main/resources` 下创建 `bootstrap.yml`(优先级高于 `application.yml`): ```yaml spring: application: name: nacos-config-demo # 服务名(决定 Nacos 配置的 Data ID) cloud: nacos: config: server-addr: 127.0.0.1:8848 # Nacos 服务器地址 file-extension: yaml # 配置文件格式 group: DEFAULT_GROUP # 配置分组 namespace: public # 命名空间(默认 public) # 自动刷新配置(默认 true) refresh-enabled: true # 共享配置(可选) shared-configs: - data-id: common.yaml group: DEFAULT_GROUP refresh: true ``` > **配置说明** > - `spring.application.name` 决定 Nacos 中的 Data ID(如 `nacos-config-demo.yaml`)[^4] > - `shared-configs` 支持加载多个共享配置(如数据库配置) --- #### 步骤 3:在 Nacos 控制台添加配置 1. 访问 Nacos 控制台(`http://localhost:8848/nacos`,默认账号 `nacos/nacos`) 2. 进入 **配置管理 → 配置列表** 3. 点击 **+** 新建配置: - **Data ID**: `nacos-config-demo.yaml`(格式:`${spring.application.name}.${file-extension}`) - **Group**: `DEFAULT_GROUP` - **配置格式**: YAML - **内容示例**: ```yaml app: version: 1.0.0 feature: enabled: true ``` --- #### 步骤 4:在代码中使用配置 ```java import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RefreshScope // 启用配置动态刷新 public class ConfigController { @Value("${app.version}") // 注入配置值 private String appVersion; @GetMapping("/version") public String getVersion() { return "当前版本: " + appVersion; } } ``` > **动态刷新** > 修改 Nacos 中的配置后,服务无需重启,`@RefreshScope` 会自动更新配置值[^1] --- #### 步骤 5:启动应用并验证 1. 启动应用: ```bash mvn spring-boot:run ``` 2. 访问 `http://localhost:8080/version` 查看配置值 3. 在 Nacos 控制台修改 `app.version` 并发布 4. 刷新页面,观察配置是否实时更新 --- ### 配置规则说明 在 Nacos 中,配置文件的 Data ID 遵循规则: $$ \text{Data ID} = \text{spring.application.name} + \text{file-extension} $$ 例如: - 服务名: `user-service` - 文件格式: `yaml` - Data ID: `user-service.yaml`[^4] --- ### 常见问题解决 1. **配置加载失败** - 检查 `bootstrap.yml` 是否存在且配置正确 - 确认 Nacos 控制台配置的 Data ID 和分组匹配 2. **动态刷新不生效** - 确保添加 `@RefreshScope` 注解 - 检查 `refresh-enabled: true`(默认开启) 3. **多环境配置** 使用 `spring.profiles.active` 指定环境,Data ID 格式为: $$ \text{Data ID} = \text{spring.application.name} + \text{-} + \text{profile} + \text{.} + \text{file-extension} $$ 例如:`nacos-config-demo-dev.yaml` --- ### 示例项目结构 ``` src/ ├── main/ │ ├── java/ │ │ └── com/example/ │ │ ├── ConfigController.java │ │ └── DemoApplication.java │ └── resources/ │ ├── bootstrap.yml # Nacos 配置 │ └── application.yml # 应用配置 pom.xml ``` 通过以上步骤,您的 Spring Boot 3.x 应用即可集成 Nacos 配置中心,实现配置的动态管理和更新[^1][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沉默的老李

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值