Java 后端手册JAVA BACKEND

CHAPTER 03工程层 · SPRING BOOT

Spring Boot

自动配置、IoC/DI、Bean 生命周期、Starter 与常用注解。理解"约定优于配置"如何让工程化开箱即用。

开始阅读难度进阶先修第一、二章约3小时
03.1

IoC 与 DI 思想

控制反转(IoC)把对象的创建与依赖组装交给容器;依赖注入(DI)是具体实现:对象不自己 new 依赖,而是由容器注入。降低耦合、便于替换与测试。

为什么要 DI

类只声明"我需要什么接口",由容器决定给哪个实现。换实现、做 mock 测试都无需改业务代码。

03.2

@SpringBootApplication

这个组合注解开启自动配置、组件扫描与配置类。启动类的 main 调 SpringApplication.run 拉起整个容器。

@SpringBootApplication   // = @Configuration + @EnableAutoConfiguration + @ComponentScan
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
03.3

声明 Bean

用 @Component(及其特化 @Service/@Repository/@Controller)或 @Bean(在 @Configuration 里)把对象交给容器管理。

@Service
public class OrderService {
    private final OrderRepository repo;
    public OrderService(OrderRepository repo) { this.repo = repo; }
}

@Configuration
public class AppConfig {
    @Bean
    public Clock clock() { return Clock.systemUTC(); }
}
03.4

Bean 作用域

默认单例(singleton,全程一个实例);还有 prototype(每次新实例)、request、session(Web 范围)。无状态服务用单例,有状态需谨慎。

作用域生命周期适用
singleton容器级单例无状态服务/DAO
prototype每次注入新建有状态对象
request每个 HTTP 请求Web 上下文
03.5

依赖注入方式

构造器注入(推荐,不可变、必填)、Setter 注入(可选)、字段注入(@Autowired,不推荐,难测试)。

@Service
public class UserService {
    private final UserRepository repo;
    public UserService(UserRepository repo) {  // 构造器注入
        this.repo = repo;
    }
}
优先构造器注入

配合 final 字段保证依赖不可变、必填,且便于单元测试直接传 mock。

03.6

自动配置原理

Spring Boot 扫描 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,按条件(类路径、已有 Bean、配置开关)装配 Bean,免去大量 XML。

@AutoConfiguration
@ConditionalOnClass(DataSource.class)
@ConditionalOnMissingBean(DataSource.class)
public class DataSourceAutoConfiguration { /* 条件满足才生效 */ }
03.7

配置外部化

配置写 application.yml,按 profile(dev/test/prod)覆盖;敏感信息用环境变量或配置中心,不进代码库。

spring:
  datasource:
    url: ${DB_URL:jdbc:h2:mem:testdb}
    username: ${DB_USER:sa}
---
spring:
  config:
    activate:
      on-profile: prod
别硬编码密钥

密码、token 走环境变量或 Vault/配置中心,CI 注入。提交到仓库是重大安全事故。

03.8

常见陷阱与 FAQ

循环依赖怎么破?

单例构造器循环依赖 Spring 启动会报错。用 @Lazy 延迟、或重构把公共逻辑抽到第三方类打破环。更好的做法是重新设计依赖方向。

为什么字段注入不推荐?

它绕过了构造器,导致类在无容器环境下难以实例化与测试,且隐藏了必填依赖。构造器注入更显式。

多实现注入冲突怎么办?

用 @Qualifier 指定名字,或让一个实现 @Primary。也能用 List<接口> 注入所有实现做策略选择。

03.9

实战练习与资源

延伸资源