Spring Boot 的目标不是替代 Spring,而是让 Spring 应用更容易启动、配置、运行和交付。它把大量常见选择做成默认约定:依赖怎么选、Tomcat 怎么启动、JSON 怎么序列化、配置从哪里读取、健康检查怎么暴露、应用如何打成可执行 Jar。

本文不做百科式穷举。Spring Boot 覆盖 Web、数据访问、消息、缓存、安全、可观测性、测试、容器镜像、AOT、原生镜像等很多方向,全部展开会变成官方手册。这里聚焦日常 Java 后端项目最常用、最值得先掌握的核心功能。

总览:Spring Boot 解决什么问题#

一个传统 Spring 项目通常要先处理很多基础工作:引入一堆依赖、配置 DispatcherServlet、配置 JSON、配置数据源、配置事务、配置日志、配置打包方式。Spring Boot 把这些重复工作收敛成三件事:

  1. 用 Starter 组织依赖,例如 spring-boot-starter-webspring-boot-starter-data-jpa
  2. 用自动配置根据 classpath 和配置文件创建合适的 Bean。
  3. 用生产级能力补齐健康检查、指标、日志、外部化配置和可执行包。

最小应用大概是这样:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

@SpringBootApplication 通常可以理解为三个能力的组合:组件扫描、配置类声明、自动配置入口。也就是说,项目启动后,Spring Boot 会扫描你的 Controller、Service、Repository,并按条件装配 Web、JSON、数据库、事务、日志等基础设施。

1. Starter:把常用依赖打包成入口#

Starter 是 Spring Boot 的第一层体验优化。你不需要自己逐个判断 Spring MVC、Jackson、Tomcat、Validation 等依赖的兼容版本,只要引入对应 Starter。

典型 Maven 配置如下:

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

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

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

常见 Starter 可以按场景理解:

场景Starter解决的问题
Web APIspring-boot-starter-webSpring MVC、嵌入式 Servlet 容器、JSON
响应式 Webspring-boot-starter-webfluxWebFlux、Reactor、Netty 场景
数据库 ORMspring-boot-starter-data-jpaJPA、Hibernate、Repository 抽象
JDBCspring-boot-starter-jdbcDataSource、JdbcTemplate、事务
参数校验spring-boot-starter-validationBean Validation 注解校验
安全spring-boot-starter-security认证、授权、安全过滤链
监控spring-boot-starter-actuator健康检查、指标、管理端点
测试spring-boot-starter-testJUnit、Spring Test、MockMvc 等测试工具

2. 自动配置:少写配置,但不是魔法#

自动配置的核心逻辑是“条件成立才创建 Bean”。例如:

  • classpath 里有 Spring MVC,Boot 会配置 Web MVC 相关组件。
  • classpath 里有 Jackson,Boot 会配置 JSON 序列化。
  • 配置了 spring.datasource.*,Boot 会尝试创建 DataSource
  • 你自己声明了同类型 Bean,默认配置通常会退让。

这就是 Spring Boot 好用的关键:默认值先帮你跑起来,但你仍然可以覆盖默认配置。

例如自定义 JSON 时间格式:

spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: Asia/Shanghai

如果需要更强控制,可以自己声明 Bean:

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JsonConfig {
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.findAndRegisterModules();
        return mapper;
    }
}

实际排查自动配置时,Actuator 的 conditions 端点和启动日志很有用:它们能告诉你某个自动配置为什么生效或没有生效。

3. Web API:快速提供 HTTP 接口#

Spring Boot 最常见的用途是写 REST API。一个完整的 Controller 可以很短:

package com.example.demo.user;

import jakarta.validation.Valid;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {
    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping
    public List<UserResponse> list() {
        return userService.list();
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public UserResponse create(@Valid @RequestBody CreateUserRequest request) {
        return userService.create(request);
    }

    public record CreateUserRequest(
            @NotBlank String name,
            @Email String email
    ) {}

    public record UserResponse(Long id, String name, String email) {}
}

这里展示了几个常用点:

  • @RestController:返回对象会自动序列化为 JSON。
  • @RequestMapping@GetMapping@PostMapping:声明路由。
  • @RequestBody:读取 JSON 请求体。
  • @Valid:触发参数校验。
  • record:适合定义简单 DTO。

4. 业务层与依赖注入:把规则放在正确位置#

Controller 不应该塞太多业务逻辑。常见分层是 Controller 处理 HTTP 协议细节,Service 处理业务规则,Repository 处理数据访问。

package com.example.demo.user;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public List<UserController.UserResponse> list() {
        return userRepository.findAll().stream()
                .map(user -> new UserController.UserResponse(
                        user.getId(), user.getName(), user.getEmail()))
                .toList();
    }

    @Transactional
    public UserController.UserResponse create(UserController.CreateUserRequest request) {
        if (userRepository.existsByEmail(request.email())) {
            throw new IllegalArgumentException("邮箱已经存在");
        }

        User user = new User();
        user.setName(request.name());
        user.setEmail(request.email());
        User saved = userRepository.save(user);

        return new UserController.UserResponse(saved.getId(), saved.getName(), saved.getEmail());
    }
}

这里的关键不是注解多,而是职责清晰:业务规则放在 Service,事务边界也通常放在 Service。

5. 数据访问:JPA、JDBC 和事务#

Spring Boot 会根据依赖和配置自动创建数据源、事务管理器以及常用数据访问组件。

如果使用 JPA,一个实体和 Repository 可以这样写:

package com.example.demo.user;

import jakarta.persistence.*;

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false, unique = true)
    private String email;

    public Long getId() { return id; }
    public String getName() { return name; }
    public String getEmail() { return email; }
    public void setName(String name) { this.name = name; }
    public void setEmail(String email) { this.email = email; }
}
package com.example.demo.user;

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
    boolean existsByEmail(String email);
}

数据库配置放在 application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=Asia/Shanghai
    username: demo
    password: demo-password
  jpa:
    hibernate:
      ddl-auto: validate
    open-in-view: false

生产环境不建议依赖 ddl-auto: update 自动改表。更常见的做法是使用 Flyway 或 Liquibase 管理数据库变更。

6. 外部化配置:同一份代码跑不同环境#

Spring Boot 的配置可以来自配置文件、环境变量、命令行参数、配置中心等。最常见的是用 profile 区分环境:

# application.yml
spring:
  application:
    name: user-service

server:
  port: 8080

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
# application-prod.yml
spring:
  datasource:
    url: ${DB_URL}
    username: ${DB_USER}
    password: ${DB_PASSWORD}

启动时指定环境:

java -jar app.jar --spring.profiles.active=prod

这套机制的价值是:代码包不变,运行环境变。数据库地址、端口、日志级别、第三方密钥都应该从外部注入,而不是写死在代码里。

7. 参数校验和统一异常处理#

参数校验能把错误挡在业务逻辑之前。DTO 上写约束,Controller 入参加 @Valid,Spring Boot 就会自动触发校验。

统一异常处理可以让 API 错误格式稳定:

package com.example.demo.common;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestControllerAdvice
public class ApiExceptionHandler {
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ErrorResponse handleValidation(MethodArgumentNotValidException ex) {
        List<String> messages = ex.getBindingResult().getFieldErrors().stream()
                .map(error -> error.getField() + ": " + error.getDefaultMessage())
                .toList();
        return new ErrorResponse("VALIDATION_FAILED", messages);
    }

    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseStatus(HttpStatus.CONFLICT)
    public ErrorResponse handleConflict(IllegalArgumentException ex) {
        return new ErrorResponse("BUSINESS_CONFLICT", List.of(ex.getMessage()));
    }

    public record ErrorResponse(String code, List<String> messages) {}
}

这比在每个 Controller 里手动 try-catch 更稳定,也更利于前端和调用方处理错误。

8. Actuator:上线后要能看见应用状态#

Spring Boot Actuator 提供生产级管理端点。加入依赖后,可以暴露健康检查、指标、日志级别、线程、映射关系等信息。

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

常用配置:

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  endpoint:
    health:
      probes:
        enabled: true
      show-details: when_authorized

常见端点:

端点作用
/actuator/health健康检查,常用于负载均衡和 Kubernetes 探针
/actuator/info应用信息
/actuator/metricsJVM、HTTP、系统等指标入口
/actuator/prometheusPrometheus 抓取指标
/actuator/loggers查看或调整日志级别
/actuator/mappings查看请求路径和 Handler 映射

注意:Actuator 不应该无脑全量暴露到公网。生产环境通常只开放必要端点,并配合认证、内网访问或网关限制。

9. 测试:从单元测试到接口测试#

Spring Boot 提供了测试切片和完整上下文测试。接口层常用 MockMvc

package com.example.demo.user;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(UserController.class)
class UserControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @Test
    void listUsersShouldReturnOk() throws Exception {
        mockMvc.perform(get("/api/users"))
                .andExpect(status().isOk());
    }
}

如果要启动完整 Spring 容器,可以使用 @SpringBootTest。如果测试数据库、Redis、Kafka 等外部依赖,Testcontainers 是更接近真实环境的选择。

10. 打包部署:一个 Jar 就能运行#

Spring Boot 可以把应用打成可执行 Jar:

./mvnw clean package
java -jar target/demo-0.0.1-SNAPSHOT.jar

也可以用 Maven 或 Gradle 插件构建 OCI 容器镜像:

./mvnw spring-boot:build-image

这让部署模型变得直接:同一个应用可以跑在虚拟机、Docker、Kubernetes 或传统服务器上。生产环境真正要补齐的是配置注入、日志采集、指标采集、健康检查和发布回滚策略。

哪些功能可以后学#

有些功能很重要,但不一定是入门第一天就要掌握:

  • WebFlux:适合高并发 IO 和响应式链路,不是所有 Web 项目都需要。
  • Spring Security 深度配置:认证授权很重要,但可以在理解 Web 和配置后再系统学习。
  • 消息队列:Kafka、RabbitMQ、Pulsar 等要结合业务异步模型学习。
  • AOT 和 GraalVM Native Image:适合对启动速度、内存和部署形态有要求的场景。
  • 自定义 Starter:适合平台化、组件化或公司内部基础库建设。

总结#

Spring Boot 的核心价值可以概括为一句话:用约定和自动配置减少基础设施样板代码,同时保留 Spring 生态的扩展能力。

新手优先掌握这条主线就够了:

  1. 用 Starter 引入场景能力。
  2. @SpringBootApplication 启动应用。
  3. 用 Controller、Service、Repository 组织业务代码。
  4. application.yml 和 profile 管理环境差异。
  5. 用 Validation 和统一异常处理稳定 API 行为。
  6. 用 Actuator、日志和指标支撑上线后的排查。
  7. 用测试和可执行 Jar 把应用可靠交付出去。

等这条主线跑通后,再按项目需要深入安全、缓存、消息、批处理、响应式、容器镜像和原生镜像。

参考资料#

  • Spring Boot 官方文档:https://docs.spring.io/spring-boot/index.html
  • Spring Boot Developing with Spring Boot:https://docs.spring.io/spring-boot/reference/using/index.html
  • Spring Boot Production-ready Features:https://docs.spring.io/spring-boot/reference/actuator/index.html
  • Spring Boot Auto-configuration:https://docs.spring.io/spring-boot/reference/features/developing-auto-configuration.html