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 配置加载优先级(从高到低):
- 命令行参数
- 操作系统环境变量
- application-{profile}.properties(外部)
- application.properties(外部)
- application-{profile}.properties(classpath)
- 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 配置数据源
spring:
datasource:
url: jdbc:mysql:
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
思考题
@SpringBootApplication 的三个组成注解各自的具体作用是什么?
- Spring Boot 如何处理循环依赖问题?
- 如何自定义一个 Starter 模块?
- Actuator 的
/health 端点在生产环境中如何安全暴露?