入门到进阶教程

知识库
知识库文档
/tech-stacks/spring-boot/tutorial/入门到进阶教程.md

文档

Spring Boot 入门到进阶教程

第一章:Spring Boot 核心概念

1.1 自动配置原理

Spring Boot 的自动配置通过 @SpringBootApplication 注解触发,该注解包含三个关键注解:

  • @SpringBootConfiguration:标记为配置类
  • @EnableAutoConfiguration:启用自动配置机制
  • @ComponentScan:扫描组件
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
// 组合注解的本质
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { ... })
public @interface SpringBootApplication { }

启动时,Spring Boot 通过 spring.factories 文件加载所有 AutoConfiguration 类,根据条件注解(@ConditionalOnClass@ConditionalOnMissingBean 等)决定哪些自动配置生效。

1.2 起步依赖(Starter)

Starter 是一组依赖的集合描述符,通过 Maven 的传递依赖机制,一次性引入某个功能所需的所有 JAR。

常用 Starter:

Starter 用途
spring-boot-starter-web Web 开发(含 Tomcat + Spring MVC)
spring-boot-starter-data-jpa JPA + Hibernate 数据库操作
spring-boot-starter-security 安全认证与授权
spring-boot-starter-test 测试框架集成
spring-boot-starter-actuator 生产监控
spring-boot-starter-validation Bean Validation

1.3 外部化配置

Spring Boot 配置加载优先级(从高到低):

  1. 命令行参数
  2. 操作系统环境变量
  3. application-{profile}.properties(外部)
  4. application.properties(外部)
  5. application-{profile}.properties(classpath)
  6. application.properties(classpath)

第二章:REST API 开发实战

2.1 构建 CRUD 接口

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

    @Autowired
    private UserService userService;

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

    @GetMapping("/{id}")
    public ResponseEntity<User> get(@PathVariable Long id) {
        return userService.findById(id)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public User create(@Valid @RequestBody User user) {
        return userService.save(user);
    }

    @PutMapping("/{id}")
    public User update(@PathVariable Long id, @Valid @RequestBody User user) {
        user.setId(id);
        return userService.update(user);
    }

    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void delete(@PathVariable Long id) {
        userService.deleteById(id);
    }
}

2.2 统一异常处理

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ErrorResponse handleNotFound(ResourceNotFoundException ex) {
        return new ErrorResponse(404, ex.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ErrorResponse handleValidation(MethodArgumentNotValidException ex) {
        String message = ex.getBindingResult().getFieldErrors().stream()
            .map(e -> e.getField() + ": " + e.getDefaultMessage())
            .collect(Collectors.joining(", "));
        return new ErrorResponse(400, message);
    }

    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ErrorResponse handleGeneral(Exception ex) {
        return new ErrorResponse(500, "服务器内部错误");
    }
}

第三章:数据访问与 JPA

3.1 配置数据源

# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
    username: root
    password: ${DB_PASSWORD}
    driver-class-name: com.mysql.cj.jdbc.Driver
    hikari:
      maximum-pool-size: 10
      minimum-idle: 5

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

3.2 实体与 Repository

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

    @Column(nullable = false, length = 50)
    private String name;

    @Column(unique = true)
    private String email;

    @CreatedDate
    private LocalDateTime createdAt;

    @LastModifiedDate
    private LocalDateTime updatedAt;
}

public interface UserRepository extends JpaRepository<User, Long> {

    Optional<User> findByEmail(String email);

    @Query("SELECT u FROM User u WHERE u.name LIKE %:keyword%")
    List<User> searchByName(@Param("keyword") String keyword);

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

第四章:Actuator 监控

4.1 启用端点

management.endpoints.web.exposure.include=health,info,metrics,prometheus
management.endpoint.health.show-details=always
management.metrics.export.prometheus.enabled=true

4.2 自定义健康检查

@Component
public class DatabaseHealthIndicator implements HealthIndicator {
    @Autowired
    private DataSource dataSource;

    @Override
    public Health health() {
        try (Connection conn = dataSource.getConnection()) {
            if (conn.isValid(1000)) {
                return Health.up()
                    .withDetail("database", "MySQL")
                    .withDetail("status", "connected")
                    .build();
            }
        } catch (Exception e) {
            return Health.down()
                .withDetail("error", e.getMessage())
                .build();
        }
        return Health.down().build();
    }
}

第五章:打包与部署

5.1 Fat JAR 打包

./mvnw clean package -DskipTests
java -jar target/demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod

5.2 Docker 部署

FROM openjdk:17-slim
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]
docker build -t myapp:latest .
docker run -d -p 8080:8080 -e SPRING_PROFILES_ACTIVE=prod myapp:latest

思考题

  1. @SpringBootApplication 的三个组成注解各自的具体作用是什么?
  2. Spring Boot 如何处理循环依赖问题?
  3. 如何自定义一个 Starter 模块?
  4. Actuator 的 /health 端点在生产环境中如何安全暴露?

信息

路径
/tech-stacks/spring-boot/tutorial/入门到进阶教程.md
更新时间
2026/5/30