Spring之我见 - Spring Boot Starter 自动装配原理

欢迎光临小站:致橡树

Spring Boot Starter 的核心设计理念是 约定优于配置 ,其核心实现基于 自动配置(Auto-Configuration)条件化注册(Conditional Registration)。以下是其生效原理:

约定大于配置

通过预定义合理的默认行为和规范,减少开发者需要手动配置的步骤。比较显著的变化就是减少XML配置。还有一些实际体现如下所示:

  • 项目结构约定

    • 默认目录结构 :如 src/main/java 存放代码,src/main/resources 存放配置文件。

    • 配置文件命名application.propertiesapplication.yml 自动被加载,无需显式指定路径。

  • 自动配置(Auto-Configuration)

    • 条件化 Bean 注册 :根据类路径依赖(如存在 DataSource 类)自动配置数据库连接池

    • 默认参数值 :如嵌入式 Tomcat 默认端口为 8080,无需手动指定。

  • Starter 依赖

    • 依赖聚合 :引入 spring-boot-starter-web 即自动包含 Web 开发所需的所有依赖(如 Tomcat、Jackson、Spring MVC)。

    • 开箱即用:无需手动管理版本兼容性。

  • RESTful 路由映射

    • 注解驱动 :通过 @GetMapping("/path") 即可定义接口,无需在 XML 中配置路由规则。

自动配置机制

触发阶段:@EnableAutoConfiguration

  • 应用启动时,@SpringBootApplication 组合了 @EnableAutoConfiguration,触发自动配置流程。

  • AutoConfigurationImportSelector 被调用,负责加载所有候选的自动配置类。

    public String[] selectImports(AnnotationMetadata metadata) {
    // 1. 加载所有候选自动配置类
    List<String> configurations = getCandidateConfigurations();
    // 2. 去重、过滤、排序
    configurations = removeDuplicates(configurations);
    configurations = filter(configurations, autoConfigurationMetadata);
    return configurations.toArray(new String[0]);
    }

**加载与筛选:**spring.factories

  • 加载所有候选配置类

    从所有 META-INF/spring.factories 文件中读取 EnableAutoConfiguration 对应的配置类。在 Spring Boot 3.x 中,自动配置类的加载方式从 spring.factories 过渡到 AutoConfiguration.imports,并引入了 ImportCandidates 类来处理这一变化。

  • 去重与过滤

    移除重复的配置类,并通过条件注解(如 @ConditionalOnClass ,@ConditionalOnMissingBean ) 有选择的保留当前环境的配置类。

    • @ConditionalOnClass:类路径存在指定类时生效

    • @ConditionalOnMissingBean:容器中不存在指定 Bean 时生效

    • @ConditionalOnProperty:配置属性匹配时生效

  • 排序

    根据 @AutoConfigureOrder@AutoConfigureAfter 调整配置类的加载顺序。

Bean 注册

  • 筛选后的自动配置类被解析为标准的 @Configuration 类。

  • 每个配置类中的 @Bean 方法根据条件注解动态注册 Bean 到 Spring 容器。

编写自定义Spring Boot Starter

项目结构规划

建议分为两个模块:

  1. 自动配置模块 :包含核心逻辑和自动配置类(如 hello-spring-boot-autoconfigure)。

  2. Starter模块 :空项目,仅作为依赖聚合(如 hello-spring-boot-starter)。

    hello-spring-boot-starter-parent(父POM)
    ├── hello-spring-boot-autoconfigure(自动配置模块)
    └── hello-spring-boot-starter(Starter模块)

    hello-spring-boot-starter/
    ├── hello-spring-boot-autoconfigure/
    │ ├── src/
    │ │ ├── main/
    │ │ │ ├── java/com/example/autoconfigure/
    │ │ │ │ ├── HelloAutoConfiguration.java
    │ │ │ │ ├── HelloProperties.java
    │ │ │ │ └── HelloService.java
    │ │ │ └── resources/
    │ │ │ └── META-INF/
    │ │ │ └── spring.factories
    │ │ └── test/
    │ └── pom.xml
    ├── hello-spring-boot-starter/
    │ └── pom.xml
    └── pom.xml

创建自动配置模块(hello-spring-boot-autoconfigure)

添加Maven依赖

复制代码
<!-- pom.xml -->
<dependencies>
    <!-- Spring Boot 自动配置基础依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
        <version>3.1.5</version>
    </dependency>
    <!-- 可选:配置属性处理 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <version>3.1.5</version>
        <optional>true</optional>
    </dependency>
</dependencies>

定义核心服务类

复制代码
public class HelloService {
    private String message = "Hello, World!";  // 默认消息

    public String sayHello() {
        return message;
    }

    // Getter和Setter用于通过配置修改message
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }
}

定义配置属性类(可选)

复制代码
@ConfigurationProperties(prefix = "hello")
public class HelloProperties {
    private String message = "Hello, World!";

    // Getter和Setter
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }
}

编写自动配置类

复制代码
@Configuration
@EnableConfigurationProperties(HelloProperties.class)  // 启用配置属性
@ConditionalOnClass(HelloService.class)  // 当HelloService在类路径时生效
public class HelloAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean  // 当用户未自定义HelloService时生效
    public HelloService helloService(HelloProperties properties) {
        HelloService service = new HelloService();
        service.setMessage(properties.getMessage());
        return service;
    }
}

注册自动配置

resources/META-INF/ 下创建 spring.factories 文件:

复制代码
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.autoconfigure.HelloAutoConfiguration

创建Starter模块(hello-spring-boot-starter)

添加Maven依赖

复制代码
<!-- pom.xml -->
<dependencies>
    <!-- 引入自动配置模块 -->
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>hello-spring-boot-autoconfigure</artifactId>
        <version>1.0.0</version>
    </dependency>
</dependencies>

使用自定义Starter

在应用中引入Starter依赖

复制代码
<!-- 用户项目的pom.xml -->
<dependency>
    <groupId>com.example</groupId>
    <artifactId>hello-spring-boot-starter</artifactId>
    <version>1.0.0</version>
</dependency>

在代码中注入Bean

复制代码
@RestController
public class HelloController {
    @Autowired
    private HelloService helloService;

    @GetMapping("/hello")
    public String hello() {
        return helloService.sayHello();
    }
}

自定义配置(可选)

application.properties 中修改消息:

复制代码
hello.message=你好, Spring Boot!
相关推荐
白鸽(二般)4 分钟前
eclipse常用快捷键
java·ide·eclipse
猿java7 分钟前
10种常见的架构风格,你用过几种?
java·分布式·架构
virtuousOne9 分钟前
spring Ai---向量知识库(一)
java
刘大猫2612 分钟前
Arthas stack (输出当前方法被调用的调用路径)
java·人工智能·数据分析
程序媛学姐12 分钟前
SpringBoot Actuator指标收集:Micrometer与Prometheus集成
spring boot·后端·prometheus
走向自由15 分钟前
Spring 学习笔记之 @Transactional详解
spring·spring aop·transactional注解
网络技术 notebook16 分钟前
java输出、输入语句
java·开发语言
LiuYaoheng20 分钟前
深入理解Java包装类:自动装箱拆箱与缓存池机制
java·缓存
欲儿22 分钟前
RabbitMQ原理及代码示例
java·spring boot·后端·rabbitmq
林 子24 分钟前
Spring Boot自动装配原理(源码详细剖析!)
spring boot·后端