Featured image of post Spring Boot 4 从入门到实战:自动配置、Web 开发与生产部署
Java

Spring Boot 4 从入门到实战:自动配置、Web 开发与生产部署

Spring Boot 4 从入门到实战:自动配置、Web 开发与生产部署

前言

Spring Boot 是 Spring 生态中最受欢迎的框架,它通过"约定优于配置"的理念,让开发者能快速创建独立运行的、生产级的 Spring 应用。目前最新版本为 Spring Boot 4.1.0(2026 年 6 月发布),要求 Java 17+,基于 Spring Framework 7,全面拥抱 Jakarta EE。

1. 核心特性

特性说明
自动配置根据引入的依赖自动配置 Bean
起步依赖Starter 依赖简化 Maven/Gradle 配置
内嵌服务器内嵌 Tomcat/Jetty/Undertow,无需外部部署
Actuator生产级监控和管理端点
外部化配置支持 YAML/Properties/环境变量/命令行参数
无代码生成不生成代码,不修改字节码

2. 快速开始

2.1 创建项目

# 使用 Spring Initializr(推荐)
# https://start.spring.io

# 或使用命令行
curl https://start.spring.io/starter.tgz \
  -d type=maven-project \
  -d language=java \
  -d bootVersion=4.1.0 \
  -d baseDir=myapp \
  -d groupId=com.example \
  -d artifactId=myapp \
  -d name=myapp \
  -d packageName=com.example.myapp \
  -d javaVersion=17 \
  -d dependencies=web,data-jpa,mysql,lombok,actuator \
| tar -xzvf -

2.2 pom.xml 核心依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>4.1.0</version>
</parent>

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

    <!-- 数据库 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
    </dependency>

    <!-- Redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

    <!-- 参数校验 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>

    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

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

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

2.3 启动类

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

3. 自动配置原理

3.1 启动流程

@SpringBootApplication
    ├── @SpringBootConfiguration  → 标记为配置类
    ├── @EnableAutoConfiguration  → 开启自动配置
    │   └── @Import(AutoConfigurationImportSelector)
    │       └── 读取 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
    └── @ComponentScan            → 扫描当前包及子包

3.2 自动配置条件注解

@ConditionalOnClass          // 类路径下存在指定类
@ConditionalOnMissingClass   // 类路径下不存在指定类
@ConditionalOnBean           // 容器中存在指定 Bean
@ConditionalOnMissingBean    // 容器中不存在指定 Bean
@ConditionalOnProperty       // 配置属性满足条件
@ConditionalOnResource       // 类路径下存在指定资源
@ConditionalOnWebApplication // 是 Web 应用

3.3 查看自动配置报告

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

# 或在配置中添加
debug=true

日志中会显示:

  • Positive matches — 匹配成功的自动配置
  • Negative matches — 未匹配的自动配置
  • Unconditional classes — 无条件配置的类

4. 配置文件

4.1 application.yml

server:
  port: 8080
  servlet:
    context-path: /api

spring:
  # 数据源
  datasource:
    url: jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: ${DB_PASSWORD:default}
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5

  # JPA
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
    properties:
      hibernate:
        format_sql: true

  # Redis
  data:
    redis:
      host: localhost
      port: 6379
      password: ${REDIS_PASSWORD:}
      database: 0

  # Jackson
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: Asia/Shanghai
    default-property-inclusion: non_null

# 自定义配置
app:
  name: My Application
  version: 1.0.0

# 日志
logging:
  level:
    root: INFO
    com.example.myapp: DEBUG
    org.hibernate.SQL: DEBUG
  file:
    name: logs/app.log
    max-size: 100MB
    max-history: 30

# Actuator
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  endpoint:
    health:
      show-details: always

4.2 多环境配置

# application-dev.yml    → 开发环境
# application-test.yml   → 测试环境
# application-prod.yml   → 生产环境

# 激活方式
java -jar myapp.jar --spring.profiles.active=prod

# 或环境变量
export SPRING_PROFILES_ACTIVE=prod

4.3 读取配置

// 方式一:@Value
@Value("${app.name}")
private String appName;

// 方式二:@ConfigurationProperties
@Data
@ConfigurationProperties(prefix = "app")
public class AppProperties {
    private String name;
    private String version;
    private List<String> servers;
}

// 在启动类上启用
@SpringBootApplication
@EnableConfigurationProperties(AppProperties.class)
public class MyApplication { }

5. Web 开发

5.1 RESTful Controller

@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;

    @GetMapping
    public ApiResponse<List<UserDTO>> list(@RequestParam(defaultValue = "1") int page,
                                            @RequestParam(defaultValue = "10") int size) {
        return ApiResponse.success(userService.list(page, size));
    }

    @GetMapping("/{id}")
    public ApiResponse<UserDTO> getById(@PathVariable Long id) {
        return ApiResponse.success(userService.getById(id));
    }

    @PostMapping
    public ApiResponse<UserDTO> create(@Valid @RequestBody UserCreateRequest request) {
        return ApiResponse.success(userService.create(request));
    }

    @PutMapping("/{id}")
    public ApiResponse<UserDTO> update(@PathVariable Long id,
                                        @Valid @RequestBody UserUpdateRequest request) {
        return ApiResponse.success(userService.update(id, request));
    }

    @DeleteMapping("/{id}")
    public ApiResponse<Void> delete(@PathVariable Long id) {
        userService.delete(id);
        return ApiResponse.success(null);
    }
}

5.2 统一响应封装

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ApiResponse<T> {
    private int code;
    private String message;
    private T data;

    public static <T> ApiResponse<T> success(T data) {
        return new ApiResponse<>(200, "OK", data);
    }

    public static <T> ApiResponse<T> error(int code, String message) {
        return new ApiResponse<>(code, message, null);
    }
}

5.3 全局异常处理

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    // 参数校验异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ApiResponse<Void> handleValidation(MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getFieldErrors().stream()
            .map(fe -> fe.getField() + ": " + fe.getDefaultMessage())
            .collect(Collectors.joining(", "));
        return ApiResponse.error(400, message);
    }

    // 业务异常
    @ExceptionHandler(BusinessException.class)
    public ApiResponse<Void> handleBusiness(BusinessException e) {
        return ApiResponse.error(e.getCode(), e.getMessage());
    }

    // 未捕获异常
    @ExceptionHandler(Exception.class)
    public ApiResponse<Void> handleException(Exception e) {
        log.error("Unexpected error", e);
        return ApiResponse.error(500, "服务器内部错误");
    }
}

5.4 请求参数校验

@Data
public class UserCreateRequest {

    @NotBlank(message = "用户名不能为空")
    @Size(min = 2, max = 20, message = "用户名长度 2-20")
    private String username;

    @NotBlank(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")
    private String email;

    @NotNull(message = "年龄不能为空")
    @Min(value = 1, message = "年龄最小 1")
    @Max(value = 150, message = "年龄最大 150")
    private Integer age;
}

5.5 拦截器

@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        String token = request.getHeader("Authorization");
        if (token == null || !validateToken(token)) {
            response.setStatus(401);
            response.getWriter().write("{\"code\":401,\"message\":\"未授权\"}");
            return false;
        }
        return true;
    }
}

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor)
            .addPathPatterns("/api/**")
            .excludePathPatterns("/api/auth/**");
    }
}

5.6 跨域配置

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
            .allowedOrigins("http://localhost:3000")
            .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
            .allowedHeaders("*")
            .allowCredentials(true)
            .maxAge(3600);
    }
}

6. 数据访问

6.1 JPA 实体

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

    @Column(nullable = false, unique = true, length = 50)
    private String username;

    @Column(nullable = false)
    private String email;

    @Column(nullable = false)
    private Integer age;

    @CreationTimestamp
    private LocalDateTime createdAt;

    @UpdateTimestamp
    private LocalDateTime updatedAt;
}

6.2 JPA Repository

public interface UserRepository extends JpaRepository<User, Long> {

    Optional<User> findByUsername(String username);

    List<User> findByAgeBetween(Integer minAge, Integer maxAge);

    @Query("SELECT u FROM User u WHERE u.email LIKE %:keyword% OR u.username LIKE %:keyword%")
    Page<User> search(@Param("keyword") String keyword, Pageable pageable);

    @Modifying
    @Query("UPDATE User u SET u.email = :email WHERE u.id = :id")
    int updateEmail(@Param("id") Long id, @Param("email") String email);
}

6.3 Redis 缓存

@Service
@RequiredArgsConstructor
public class UserService {

    private final UserRepository userRepository;
    private final RedisTemplate<String, Object> redisTemplate;

    // 使用 RedisTemplate
    public UserDTO getById(Long id) {
        String key = "user:" + id;
        UserDTO cached = (UserDTO) redisTemplate.opsForValue().get(key);
        if (cached != null) return cached;

        User user = userRepository.findById(id)
            .orElseThrow(() -> new BusinessException(404, "用户不存在"));
        UserDTO dto = convertToDTO(user);
        redisTemplate.opsForValue().set(key, dto, 30, TimeUnit.MINUTES);
        return dto;
    }

    // 使用 Spring Cache 注解
    @Cacheable(value = "users", key = "#id")
    public UserDTO getByIdCached(Long id) { ... }

    @CachePut(value = "users", key = "#id")
    public UserDTO update(Long id, UserUpdateRequest request) { ... }

    @CacheEvict(value = "users", key = "#id")
    public void delete(Long id) { ... }
}

7. AOP 切面

@Aspect
@Component
@Slf4j
public class LogAspect {

    @Around("@annotation(logOperation)")
    public Object around(ProceedingJoinPoint point, LogOperation logOperation) throws Throwable {
        long start = System.currentTimeMillis();
        String methodName = point.getSignature().toShortString();

        log.info("开始执行: {} - {}", logOperation.value(), methodName);

        try {
            Object result = point.proceed();
            long cost = System.currentTimeMillis() - start;
            log.info("执行完成: {} - {} ({}ms)", logOperation.value(), methodName, cost);
            return result;
        } catch (Exception e) {
            log.error("执行异常: {} - {}", logOperation.value(), methodName, e);
            throw e;
        }
    }
}

// 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogOperation {
    String value() default "";
}

8. 定时任务

@SpringBootApplication
@EnableScheduling
public class MyApplication { }

@Component
@Slf4j
public class ScheduledTasks {

    @Scheduled(cron = "0 0 2 * * ?")     // 每天凌晨 2 点
    public void dailyBackup() {
        log.info("执行每日备份...");
    }

    @Scheduled(fixedRate = 60000)         // 每 60 秒
    public void syncData() {
        log.info("同步数据...");
    }

    @Scheduled(fixedDelay = 30000)        // 上次完成后 30 秒
    public void cleanup() {
        log.info("清理任务...");
    }
}

9. 异步处理

@SpringBootApplication
@EnableAsync
public class MyApplication { }

@Configuration
public class AsyncConfig {

    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("async-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}

@Service
public class NotificationService {

    @Async("taskExecutor")
    public CompletableFuture<String> sendEmail(String to, String content) {
        // 耗时操作
        return CompletableFuture.completedFuture("sent");
    }
}

10. 生产部署

10.1 打包

# Maven 打包
mvn clean package -DskipTests

# Gradle 打包
gradle bootJar

# 运行
java -jar target/myapp-1.0.0.jar

# 指定 profile
java -jar myapp.jar --spring.profiles.active=prod

# JVM 参数
java -Xms512m -Xmx1024m -XX:+UseG1GC -jar myapp.jar

10.2 Docker 部署

FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

10.3 Actuator 监控端点

端点说明
/actuator/health健康检查
/actuator/info应用信息
/actuator/metrics指标数据
/actuator/prometheusPrometheus 格式指标
/actuator/env环境变量
/actuator/configprops配置属性
/actuator/beans所有 Bean
/actuator/mappingsURL 映射
/actuator/loggers日志级别管理
/actuator/threaddump线程 dump
/actuator/heapdump堆 dump

11. 常用 Starter 一览

Starter用途
spring-boot-starter-webWeb/RESTful
spring-boot-starter-data-jpaJPA 数据访问
spring-boot-starter-data-redisRedis
spring-boot-starter-data-mongodbMongoDB
spring-boot-starter-security安全认证
spring-boot-starter-validation参数校验
spring-boot-starter-mail邮件发送
spring-boot-starter-quartz定时任务
spring-boot-starter-websocketWebSocket
spring-boot-starter-actuator监控管理
spring-boot-starter-test单元测试
mybatis-plus-spring-boot3-starterMyBatis-Plus

12. Spring Boot 版本选择

版本状态Java 要求Spring Framework
4.1.x (推荐)最新,OSS 支持到 2027.7Java 17-267.0.x
4.0.x稳定Java 17-267.0.x
3.5.xOSS 支持到 2026.6Java 17-246.2.x
3.2.x已停止 OSS 支持Java 17-216.1.x
2.7.x已停止支持Java 8/11/175.3.x

💡 建议:新项目直接使用 Spring Boot 4.1.x + Java 21/25。

总结

Spring Boot 核心知识点:

  • 自动配置 — 根据依赖自动配置,减少样板代码
  • 起步依赖 — Starter 一站式引入所需依赖
  • Web 开发 — RESTful API、参数校验、异常处理、拦截器
  • 数据访问 — JPA、Redis、MyBatis
  • AOP — 日志、权限、缓存等横切关注点
  • 生产特性 — Actuator 监控、多环境配置、优雅停机
  • 部署方式 — JAR 直接运行、Docker 容器化
使用 Hugo 构建
主题 StackJimmy 设计