Spring Boot的起步依赖原理

一句话理解起步依赖

起步依赖是"一键式套餐"

  • 传统Spring:点菜 → 要自己搭配(A菜+B菜+C调料)
  • Spring Boot:点套餐 → 直接给你配好(XX套餐 = 主食+配菜+饮料)

比如:spring-boot-starter-web= Tomcat + Spring MVC + Jackson + …

从传统Spring到Spring Boot的进化

传统Spring项目(Maven配置)

<!-- 要开发Web应用,需要手动配一堆依赖 -->
<dependencies>
    <!-- Spring Core -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.23</version>
    </dependency>
    
    <!-- Jackson for JSON -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.13.4</version>
    </dependency>
    
    <!-- Servlet API -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
    
    <!-- Tomcat -->
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-core</artifactId>
        <version>9.0.68</version>
    </dependency>
    <!-- 还要配几十行... -->
</dependencies>

Spring Boot项目(一键搞定)

<!-- 只需要一个起步依赖 -->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

对比

  • 行数:50+行 → 5行
  • 版本管理:手动指定 → 自动管理
  • 依赖冲突:经常发生 → 自动解决

起步依赖的目录结构

spring-boot-starter-parent
├── spring-boot-dependencies  # 版本管理
├── spring-boot-starter       # 核心启动器
├── spring-boot-starter-web   # Web启动器
├── spring-boot-starter-data-jpa  # JPA启动器
├── spring-boot-starter-security  # 安全启动器
├── spring-boot-starter-test  # 测试启动器
└── ... 50+个官方starter

起步依赖的实现原理

1. 父POM统一版本管理

spring-boot-dependencies.pom

<!-- 在Spring Boot父POM中定义了所有依赖的版本 -->
<properties>
    <activemq.version>5.16.5</activemq.version>
    <antlr2.version>2.7.7</antlr2.version>
    <appengine-sdk.version>1.9.98</appengine-sdk.version>
    <artemis.version>2.20.0</artemis.version>
    <aspectj.version>1.9.7</aspectj.version>
    <assertj.version>3.22.0</assertj.version>
    <commons-codec.version>1.15</commons-codec.version>
    <hibernate.version>5.6.10.Final</hibernate.version>
    <jackson.version>2.13.4</jackson.version>
    <jakarta-servlet.version>5.0.0</jakarta-servlet.version>
    <junit.version>4.13.2</junit.version>
    <logback.version>1.2.11</logback.version>
    <mysql.version>8.0.31</mysql.version>
    <slf4j.version>1.7.36</slf4j.version>
    <spring.version>5.3.23</spring.version>
    <tomcat.version>9.0.68</tomcat.version>
    <!-- 300+个版本定义 -->
</properties>

<!-- 依赖管理 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${revision}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <!-- ... -->
    </dependencies>
</dependencyManagement>

2. 起步依赖本身很简单

spring-boot-starter-web.pom

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.7.8</version>
    
    <dependencies>
        <!-- 1. Web核心 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        
        <!-- 2. JSON处理 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-json</artifactId>
        </dependency>
        
        <!-- 3. Tomcat服务器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        
        <!-- 4. Spring MVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
        </dependency>
        
        <!-- 5. 验证 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
    </dependencies>
</project>

注意:起步依赖不包含实际代码,只是依赖的集合

3. 层层传递的依赖

你的项目
  ↓
spring-boot-starter-web
  ├── spring-boot-starter
  │   ├── spring-boot
  │   ├── spring-boot-autoconfigure
  │   ├── spring-core
  │   ├── spring-context
  │   ├── spring-aop
  │   ├── spring-expression
  │   ├── spring-jcl
  │   └── logback-classic
  ├── spring-boot-starter-json
  │   ├── jackson-databind
  │   ├── jackson-core
  │   ├── jackson-datatype-jsr310
  │   └── jackson-module-parameter-names
  ├── spring-boot-starter-tomcat
  │   ├── tomcat-embed-core
  │   ├── tomcat-embed-el
  │   └── tomcat-embed-websocket
  ├── spring-webmvc
  │   ├── spring-web
  │   └── spring-beans
  └── spring-boot-starter-validation
      ├── hibernate-validator
      └── jakarta.validation-api

常用起步依赖详解

Starter 包含内容 典型用途
spring-boot-starter-web Tomcat + Spring MVC + Jackson Web应用、REST API
spring-boot-starter-data-jpa Hibernate + Spring Data JPA 数据库操作
spring-boot-starter-security Spring Security 安全认证授权
spring-boot-starter-test JUnit + Mockito + AssertJ 单元测试
spring-boot-starter-actuator 监控端点 应用监控
spring-boot-starter-cache 缓存抽象 缓存功能
spring-boot-starter-mail JavaMail 邮件发送
spring-boot-starter-aop Spring AOP + AspectJ 面向切面编程
spring-boot-starter-websocket WebSocket支持 实时通信
spring-boot-starter-batch Spring Batch 批处理

自定义起步依赖

案例:自定义短信服务Starter

1. 创建starter项目结构

my-sms-starter/
├── src/
│   ├── main/
│   │   ├── java/com/example/sms/
│   │   │   ├── SmsAutoConfiguration.java
│   │   │   ├── SmsProperties.java
│   │   │   ├── SmsService.java
│   │   │   └── SmsTemplate.java
│   │   └── resources/
│   │       └── META-INF/
│   │           └── spring.factories
│   └── test/
└── pom.xml

2. pom.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.example</groupId>
    <artifactId>my-sms-spring-boot-starter</artifactId>
    <version>1.0.0</version>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.8</version>
    </parent>
    
    <dependencies>
        <!-- 必须依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        
        <!-- 短信SDK -->
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>4.6.3</version>
        </dependency>
    </dependencies>
</project>

3. 配置类

// SmsProperties.java - 配置属性
@ConfigurationProperties(prefix = "sms")
public class SmsProperties {
    private String accessKeyId;
    private String accessKeySecret;
    private String signName;
    private String templateCode;
    
    // getters and setters
}

// SmsAutoConfiguration.java - 自动配置
@Configuration
@EnableConfigurationProperties(SmsProperties.class)
@ConditionalOnClass(SmsService.class)  // 当SmsService在类路径时才生效
@ConditionalOnProperty(prefix = "sms", value = "enabled", matchIfMissing = true)
public class SmsAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public SmsService smsService(SmsProperties properties) {
        return new SmsService(properties);
    }
    
    @Bean
    @ConditionalOnMissingBean
    public SmsTemplate smsTemplate(SmsService smsService) {
        return new SmsTemplate(smsService);
    }
}

4. spring.factories文件

# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.sms.SmsAutoConfiguration

5. 在其他项目中使用

<!-- 引入自定义starter -->
<dependency>
    <groupId>com.example</groupId>
    <artifactId>my-sms-spring-boot-starter</artifactId>
    <version>1.0.0</version>
</dependency>
# application.yml
sms:
  enabled: true
  access-key-id: your-access-key
  access-key-secret: your-secret
  sign-name: 公司签名
  template-code: SMS_123456
// 直接注入使用
@RestController
public class UserController {
    
    @Autowired
    private SmsTemplate smsTemplate;
    
    @PostMapping("/send-code")
    public String sendCode(@RequestParam String phone) {
        String code = generateCode();
        smsTemplate.sendVerifyCode(phone, code);
        return "验证码已发送";
    }
}

自动配置原理

1. @SpringBootApplication注解

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

// 展开后:
@SpringBootConfiguration
@EnableAutoConfiguration  // 关键!
@ComponentScan
public class MyApplication { ... }

2. @EnableAutoConfiguration原理

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)  // 核心!
public @interface EnableAutoConfiguration { ... }

AutoConfigurationImportSelector的工作流程

1. 扫描所有jar包的META-INF/spring.factories
2. 读取key为EnableAutoConfiguration的配置类
3. 根据@Conditional注解判断是否需要加载
4. 加载符合条件的配置类
5. 注册Bean到Spring容器

3. 条件注解(@Conditional)

注解 作用 示例
@ConditionalOnClass 类路径存在才生效 @ConditionalOnClass(DataSource.class)
@ConditionalOnMissingClass 类路径不存在才生效
@ConditionalOnBean 容器中有Bean才生效 @ConditionalOnBean(DataSource.class)
@ConditionalOnMissingBean 容器中没有Bean才生效
@ConditionalOnProperty 配置属性满足条件 @ConditionalOnProperty(name="sms.enabled")
@ConditionalOnWebApplication 是Web应用才生效
@ConditionalOnNotWebApplication 不是Web应用才生效
@ConditionalOnExpression SpEL表达式 @ConditionalOnExpression("#{environment['spring.datasource.url'] != null}")

查看自动配置报告

1. 开启调试模式

# application.yml
debug: true

启动时会输出:

============================
CONDITIONS EVALUATION REPORT
============================

Positive matches:  # 匹配的自动配置
-----------------
   DataSourceAutoConfiguration matched:
      - @ConditionalOnClass found required classes 'javax.sql.DataSource', 'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType' (OnClassCondition)
      - @ConditionalOnMissingBean (types: javax.sql.DataSource; SearchStrategy: all) did not find any beans (OnBeanCondition)

Negative matches:  # 未匹配的自动配置
-----------------
   ActiveMQAutoConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)

2. 查看所有自动配置

# 启动时添加参数
java -jar myapp.jar --debug

或在代码中:

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(MyApplication.class);
        app.setAdditionalProfiles("debug");
        app.run(args);
    }
}

起步依赖的优势

1. 简化配置

<!-- 传统方式:20+个依赖 -->
<!-- Spring Boot:1个starter -->

2. 版本统一管理

<!-- 传统:容易版本冲突 -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.3</version>  <!-- 版本A -->
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.3.8</version>   <!-- 版本B,可能不兼容 -->
</dependency>

<!-- Spring Boot:统一管理,保证兼容 -->

3. 自动配置

// 传统:手动配置Bean
@Configuration
public class DataSourceConfig {
    @Bean
    public DataSource dataSource() {
        // 一堆配置
    }
}

// Spring Boot:自动配置
// 只需在application.yml中配置
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: 123456

4. 快速启动

# 传统:配置半天才能跑
# Spring Boot:5分钟一个项目

🔧 实际使用技巧

1. 排除不需要的依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <!-- 排除Tomcat,使用Jetty -->
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

2. 查看依赖树

# 查看依赖关系
mvn dependency:tree

# 查看特定依赖
mvn dependency:tree -Dincludes=com.fasterxml.jackson

# Gradle
./gradlew dependencies

3. 覆盖默认版本

<!-- 在pom.xml中覆盖 -->
<properties>
    <mysql.version>8.0.33</mysql.version>
    <jackson.version>2.14.0</jackson.version>
</properties>

4. 自定义起步依赖

<!-- 公司内部通用starter -->
<dependency>
    <groupId>com.mycompany</groupId>
    <artifactId>mycompany-spring-boot-starter</artifactId>
    <version>1.0.0</version>
</dependency>

性能优化

1. 排除不必要的自动配置

@SpringBootApplication(exclude = {
    DataSourceAutoConfiguration.class,      // 如果没有数据库
    SecurityAutoConfiguration.class,        // 如果不需要安全
    MailSenderAutoConfiguration.class       // 如果不需要邮件
})
public class MyApplication { ... }

2. 懒加载

# application.yml
spring:
  main:
    lazy-initialization: true  # 启动时不初始化所有Bean

3. 指定扫描范围

@SpringBootApplication(scanBasePackages = "com.example.myapp")
public class MyApplication { ... }

企业级最佳实践

1. 分层架构的依赖管理

<!-- parent pom.xml -->
<dependencyManagement>
    <dependencies>
        <!-- 公司统一的版本管理 -->
        <dependency>
            <groupId>com.mycompany</groupId>
            <artifactId>company-bom</artifactId>
            <version>1.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<!-- module pom.xml -->
<dependencies>
    <!-- 业务模块 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.mycompany</groupId>
        <artifactId>company-common-starter</artifactId>
    </dependency>
</dependencies>

2. 多环境配置

# application-dev.yml
spring:
  datasource:
    url: jdbc:h2:mem:testdb
    
# application-prod.yml
spring:
  datasource:
    url: jdbc:mysql://prod-db:3306/app
    hikari:
      maximum-pool-size: 20

3. 监控和健康检查

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

常见问题

1. 版本冲突

# 查看冲突
mvn dependency:tree -Dverbose

# 解决:排除冲突的依赖
<exclusions>
    <exclusion>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
    </exclusion>
</exclusions>

2. 自动配置不生效

// 检查条件
@ConditionalOnClass(SomeClass.class)  // 类路径是否有?
@ConditionalOnProperty("some.property")  // 配置属性是否有?

3. 启动慢

# 使用Spring Boot DevTools热重启
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
</dependency>

总结:Spring Boot起步依赖是约定优于配置思想的完美体现。它通过:

  1. 统一版本管理:解决依赖冲突
  2. 自动配置:减少样板代码
  3. 条件装配:智能加载组件
  4. 模块化设计:按需引入功能

核心价值:让开发者专注于业务逻辑,而不是基础设施配置。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐