学习时间: 4-5小时
学习目标: 掌握Spring Boot高级特性,包括配置管理、监控、缓存、异步处理等,并完成一个完整的实战项目
详细学习清单
✅ 第一部分:Spring Boot高级配置管理(60分钟)
1. 多环境配置管理
application.yml 主配置文件
yaml
# application.yml
spring:
profiles:
active: dev # 默认使用开发环境
# 公共配置
app:
name: demo-app
version: 1.0.0
description: Spring Boot学习项目
# 日志配置
logging:
level:
com.example.demo: DEBUG
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
file:
name: logs/application.log
max-size: 10MB
max-history: 30
开发环境配置
yaml
# application-dev.yml
server:
port: 8080
spring:
datasource:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver
username: sa
password:
h2:
console:
enabled: true
path: /h2-console
# 开发工具配置
spring:
devtools:
restart:
enabled: true
additional-paths: src/main/java
exclude: static/**,public/**
生产环境配置
yaml
# application-prod.yml
server:
port: 80
spring:
datasource:
url: jdbc:mysql://localhost:3306/prod_db
username: ${DB_USERNAME:root}
password: ${DB_PASSWORD:password}
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
# 生产环境日志
logging:
level:
com.example.demo: INFO
file:
name: /var/log/demo-app/application.log
2. 配置属性绑定
配置属性类
java
// AppProperties.java
package com.example.demo.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String name;
private String version;
private String description;
private DatabaseConfig database;
private SecurityConfig security;
// Getter和Setter方法
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getVersion() { return version; }
public void setVersion(String version) { this.version = version; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public DatabaseConfig getDatabase() { return database; }
public void setDatabase(DatabaseConfig database) { this.database = database; }
public SecurityConfig getSecurity() { return security; }
public void setSecurity(SecurityConfig security) { this.security = security; }
// 内部配置类
public static class DatabaseConfig {
private String url;
private String username;
private String password;
private int maxConnections;
// Getter和Setter
public String getUrl() { return url; }
public void setUrl(String url) { this.url = url; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public int getMaxConnections() { return maxConnections; }
public void setMaxConnections(int maxConnections) { this.maxConnections = maxConnections; }
}
public static class SecurityConfig {
private String jwtSecret;
private int jwtExpiration;
private boolean enableCors;
// Getter和Setter
public String getJwtSecret() { return jwtSecret; }
public void setJwtSecret(String jwtSecret) { this.jwtSecret = jwtSecret; }
public int getJwtExpiration() { return jwtExpiration; }
public void setJwtExpiration(int jwtExpiration) { this.jwtExpiration = jwtExpiration; }
public boolean isEnableCors() { return enableCors; }
public void setEnableCors(boolean enableCors) { this.enableCors = enableCors; }
}
}
✅ 第二部分:Spring Boot监控与健康检查(60分钟)
1. Actuator监控端点
添加依赖到pom.xml
xml
<!-- Spring Boot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Micrometer Prometheus -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
Actuator配置
yaml
# application.yml
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus,env,configprops
base-path: /actuator
endpoint:
health:
show-details: always
show-components: always
info:
enabled: true
info:
env:
enabled: true
git:
mode: full
metrics:
export:
prometheus:
enabled: true
自定义健康检查
java
// CustomHealthIndicator.java
package com.example.demo.health;
import org.springframework.boot.actuator.health.Health;
import org.springframework.boot.actuator.health.HealthIndicator;
import org.springframework.stereotype.Component;
@Component
public class CustomHealthIndicator implements HealthIndicator {
@Override
public Health health() {
try {
// 检查数据库连接
checkDatabaseConnection();
// 检查外部服务
checkExternalService();
return Health.up()
.withDetail("database", "UP")
.withDetail("external-service", "UP")
.withDetail("timestamp", System.currentTimeMillis())
.build();
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.withDetail("timestamp", System.currentTimeMillis())
.build();
}
}
private void checkDatabaseConnection() {
// 模拟数据库连接检查
if (Math.random() < 0.1) { // 10%概率失败
throw new RuntimeException("数据库连接失败");
}
}
private void checkExternalService() {
// 模拟外部服务检查
if (Math.random() < 0.05) { // 5%概率失败
throw new RuntimeException("外部服务不可用");
}
}
}
2. 自定义监控指标
自定义指标
java
// CustomMetrics.java
package com.example.demo.metrics;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class CustomMetrics {
private final Counter userCreationCounter;
private final Counter userLoginCounter;
private final Timer userOperationTimer;
public CustomMetrics(MeterRegistry meterRegistry) {
this.userCreationCounter = Counter.builder("user.creation.total")
.description("用户创建总数")
.register(meterRegistry);
this.userLoginCounter = Counter.builder("user.login.total")
.description("用户登录总数")
.register(meterRegistry);
this.userOperationTimer = Timer.builder("user.operation.duration")
.description("用户操作耗时")
.register(meterRegistry);
}
public void incrementUserCreation() {
userCreationCounter.increment();
}
public void incrementUserLogin() {
userLoginCounter.increment();
}
public Timer.Sample startUserOperationTimer() {
return Timer.start();
}
public void stopUserOperationTimer(Timer.Sample sample) {
sample.stop(userOperationTimer);
}
}
✅ 第三部分:Spring Boot缓存集成(60分钟)
1. Redis缓存配置
添加Redis依赖
xml
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Redis连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
Redis配置类
java
// RedisConfig.java
package com.example.demo.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
@Configuration
@EnableCaching
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
// 使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(jackson2JsonRedisSerializer);
// Hash的key也采用StringRedisSerializer的序列化方式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30)) // 默认过期时间30分钟
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
.disableCachingNullValues();
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.build();
}
}
2. 缓存使用示例
缓存服务类
java
// CacheService.java
package com.example.demo.service;
import com.example.demo.model.User;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
@Service
public class CacheService {
private final Map<Long, User> userDatabase = new HashMap<>();
private final AtomicLong idGenerator = new AtomicLong(1);
// 缓存用户信息,key为"user::#{id}"
@Cacheable(value = "user", key = "#id")
public User getUserById(Long id) {
// 模拟数据库查询延迟
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
User user = userDatabase.get(id);
if (user == null) {
throw new RuntimeException("用户不存在, ID: " + id);
}
return user;
}
// 更新缓存
@CachePut(value = "user", key = "#user.id")
public User createUser(User user) {
user.setId(idGenerator.getAndIncrement());
userDatabase.put(user.getId(), user);
return user;
}
// 更新缓存
@CachePut(value = "user", key = "#id")
public User updateUser(Long id, User user) {
User existingUser = getUserById(id);
existingUser.setUsername(user.getUsername());
existingUser.setEmail(user.getEmail());
userDatabase.put(id, existingUser);
return existingUser;
}
// 清除缓存
@CacheEvict(value = "user", key = "#id")
public void deleteUser(Long id) {
userDatabase.remove(id);
}
// 清除所有用户缓存
@CacheEvict(value = "user", allEntries = true)
public void clearAllUserCache() {
// 清除所有用户相关缓存
}
// 获取所有用户(不缓存)
public List<User> getAllUsers() {
return userDatabase.values().stream().toList();
}
}
✅ 第四部分:异步处理与定时任务(60分钟)
1. 异步配置
异步配置类
java
// AsyncConfig.java
package com.example.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration
@EnableAsync
@EnableScheduling
public class AsyncConfig {
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("AsyncTask-");
executor.initialize();
return executor;
}
@Bean(name = "emailExecutor")
public Executor emailExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(5);
executor.setQueueCapacity(50);
executor.setThreadNamePrefix("EmailTask-");
executor.initialize();
return executor;
}
}
2. 异步服务示例
异步邮件服务
java
// EmailService.java
package com.example.demo.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
@Service
public class EmailService {
private static final Logger logger = LoggerFactory.getLogger(EmailService.class);
// 异步发送邮件
@Async("emailExecutor")
public CompletableFuture<String> sendWelcomeEmail(String email, String username) {
try {
// 模拟邮件发送延迟
Thread.sleep(2000);
String message = String.format("欢迎 %s! 您的账户已创建成功,邮箱: %s", username, email);
logger.info("发送欢迎邮件成功: {}", message);
return CompletableFuture.completedFuture("邮件发送成功");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
logger.error("邮件发送被中断", e);
return CompletableFuture.completedFuture("邮件发送失败");
} catch (Exception e) {
logger.error("邮件发送失败", e);
return CompletableFuture.completedFuture("邮件发送失败: " + e.getMessage());
}
}
// 异步批量发送邮件
@Async("emailExecutor")
public CompletableFuture<Integer> sendBulkEmails(String[] emails, String subject, String content) {
int successCount = 0;
for (String email : emails) {
try {
// 模拟邮件发送
Thread.sleep(500);
logger.info("发送邮件到: {}, 主题: {}", email, subject);
successCount++;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
} catch (Exception e) {
logger.error("发送邮件到 {} 失败: {}", email, e.getMessage());
}
}
return CompletableFuture.completedFuture(successCount);
}
}
3. 定时任务示例
定时任务服务
java
// ScheduledTaskService.java
package com.example.demo.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Service
public class ScheduledTaskService {
private static final Logger logger = LoggerLoggerFactory.getLogger(ScheduledTaskService.class);
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 每5秒执行一次
@Scheduled(fixedRate = 5000)
public void taskWithFixedRate() {
String currentTime = LocalDateTime.now().format(formatter);
logger.info("固定频率任务执行 - 当前时间: {}", currentTime);
}
// 每10秒执行一次,延迟2秒开始
@Scheduled(fixedDelay = 10000, initialDelay = 2000)
public void taskWithFixedDelay() {
String currentTime = LocalDateTime.now().format(formatter);
logger.info("固定延迟任务执行 - 当前时间: {}", currentTime);
}
// 每天凌晨2点执行
@Scheduled(cron = "0 0 2 * * ?")
public void dailyTask() {
String currentTime = LocalDateTime.now().format(formatter);
logger.info("每日定时任务执行 - 当前时间: {}", currentTime);
// 执行清理任务
cleanupExpiredData();
}
// 每周一上午9点执行
@Scheduled(cron = "0 0 9 ? * MON")
public void weeklyTask() {
String currentTime = LocalDateTime.now().format(formatter);
logger.info("每周定时任务执行 - 当前时间: {}", currentTime);
// 执行统计任务
generateWeeklyReport();
}
// 每月1号凌晨1点执行
@Scheduled(cron = "0 0 1 1 * ?")
public void monthlyTask() {
String currentTime = LocalDateTime.now().format(formatter);
logger.info("每月定时任务执行 - 当前时间: {}", currentTime);
// 执行月度清理
monthlyCleanup();
}
private void cleanupExpiredData() {
logger.info("清理过期数据...");
// 实现清理逻辑
}
private void generateWeeklyReport() {
logger.info("生成周报...");
// 实现报表生成逻辑
}
private void monthlyCleanup() {
logger.info("执行月度清理...");
// 实现月度清理逻辑
}
}
✅ 第五部分:实战项目:用户管理系统(90分钟)
1. 项目结构
bash
demo-app/
├── src/main/java/com/example/demo/
│ ├── DemoApplication.java # 启动类
│ ├── config/ # 配置类
│ │ ├── RedisConfig.java
│ │ ├── AsyncConfig.java
│ │ └── AppProperties.java
│ ├── controller/ # 控制器
│ │ └── UserController.java
│ ├── model/ # 数据模型
│ │ └── User.java
│ ├── service/ # 业务服务
│ │ ├── UserService.java
│ │ ├── CacheService.java
│ │ ├── EmailService.java
│ │ └── ScheduledTaskService.java
│ ├── health/ # 健康检查
│ │ └── CustomHealthIndicator.java
│ └── metrics/ # 监控指标
│ └── CustomMetrics.java
├── src/main/resources/
│ ├── application.yml # 主配置
│ ├── application-dev.yml # 开发环境
│ └── application-prod.yml # 生产环境
└── pom.xml
2. 完整的用户控制器
UserController.java
java
// UserController.java - 完整的用户管理控制器
package com.example.demo.controller;
import com.example.demo.model.User;
import com.example.demo.service.UserService;
import com.example.demo.service.CacheService;
import com.example.demo.service.EmailService;
import com.example.demo.metrics.CustomMetrics;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
private final CacheService cacheService;
private final EmailService emailService;
private final CustomMetrics customMetrics;
public UserController(UserService userService, CacheService cacheService,
EmailService emailService, CustomMetrics customMetrics) {
this.userService = userService;
this.cacheService = cacheService;
this.emailService = emailService;
this.customMetrics = customMetrics;
}
// 创建用户(异步发送欢迎邮件)
@PostMapping
public ResponseEntity<?> createUser(@RequestBody User user) {
try {
// 开始计时
var timerSample = customMetrics.startUserOperationTimer();
// 创建用户
User createdUser = cacheService.createUser(user);
// 异步发送欢迎邮件
CompletableFuture<String> emailResult = emailService.sendWelcomeEmail(
user.getEmail(), user.getUsername()
);
// 增加用户创建计数
customMetrics.incrementUserCreation();
// 停止计时
customMetrics.stopUserOperationTimer(timerSample);
return ResponseEntity.ok(Map.of(
"success", true,
"message", "用户创建成功",
"data", createdUser,
"emailStatus", "邮件发送中..."
));
} catch (Exception e) {
return ResponseEntity.badRequest().body(Map.of(
"success", false,
"message", e.getMessage()
));
}
}
// 获取用户(使用缓存)
@GetMapping("/{id}")
public ResponseEntity<?> getUserById(@PathVariable Long id) {
try {
var timerSample = customMetrics.startUserOperationTimer();
User user = cacheService.getUserById(id);
customMetrics.stopUserOperationTimer(timerSample);
return ResponseEntity.ok(Map.of(
"success", true,
"data", user,
"fromCache", true
));
} catch (RuntimeException e) {
return ResponseEntity.notFound().build();
}
}
// 获取所有用户
@GetMapping
public ResponseEntity<?> getAllUsers() {
List<User> users = cacheService.getAllUsers();
return ResponseEntity.ok(Map.of(
"success", true,
"data", users,
"total", users.size()
));
}
// 更新用户
@PutMapping("/{id}")
public ResponseEntity<?> updateUser(@PathVariable Long id, @RequestBody User user) {
try {
var timerSample = customMetrics.startUserOperationTimer();
User updatedUser = cacheService.updateUser(id, user);
customMetrics.stopUserOperationTimer(timerSample);
return ResponseEntity.ok(Map.of(
"success", true,
"message", "用户更新成功",
"data", updatedUser
));
} catch (RuntimeException e) {
return ResponseEntity.notFound().build();
}
}
// 删除用户
@DeleteMapping("/{id}")
public ResponseEntity<?> deleteUser(@PathVariable Long id) {
try {
cacheService.deleteUser(id);
return ResponseEntity.ok(Map.of(
"success", true,
"message", "用户删除成功"
));
} catch (RuntimeException e) {
return ResponseEntity.notFound().build();
}
}
// 批量创建用户
@PostMapping("/batch")
public ResponseEntity<?> batchCreateUsers(@RequestBody List<User> users) {
try {
List<User> createdUsers = users.stream()
.map(cacheService::createUser)
.toList();
// 异步批量发送邮件
String[] emails = createdUsers.stream()
.map(User::getEmail)
.toArray(String[]::new);
CompletableFuture<Integer> emailResult = emailService.sendBulkEmails(
emails, "账户创建成功", "您的账户已创建成功"
);
return ResponseEntity.ok(Map.of(
"success", true,
"message", "批量创建成功",
"data", createdUsers,
"count", createdUsers.size(),
"emailStatus", "批量邮件发送中..."
));
} catch (Exception e) {
return ResponseEntity.badRequest().body(Map.of(
"success", false,
"message", e.getMessage()
));
}
}
// 清除用户缓存
@DeleteMapping("/cache")
public ResponseEntity<?> clearUserCache() {
cacheService.clearAllUserCache();
return ResponseEntity.ok(Map.of(
"success", true,
"message", "用户缓存已清除"
));
}
// 获取系统状态
@GetMapping("/status")
public ResponseEntity<?> getSystemStatus() {
return ResponseEntity.ok(Map.of(
"success", true,
"data", Map.of(
"cacheEnabled", true,
"asyncEnabled", true,
"scheduledTasks", true,
"timestamp", System.currentTimeMillis()
)
));
}
}
🎯 今日学习总结
1. 掌握的核心技能
- ✅ Spring Boot多环境配置管理
- ✅ Actuator监控与健康检查
- ✅ Redis缓存集成与使用
- ✅ 异步处理与定时任务
- ✅ 自定义监控指标
2. 实战项目特点
- 多环境配置:开发、生产环境分离
- 监控体系:健康检查、指标监控、日志管理
- 性能优化:Redis缓存、异步处理
- 定时任务:数据清理、报表生成
- 完整流程:用户CRUD + 邮件通知 + 缓存管理
3. 下一步学习方向
- Spring Security安全框架
- 数据库事务管理
- 微服务架构设计
- 容器化部署(Docker)
- 云原生应用开发
学习建议
- 动手实践:每个配置都要亲自测试
- 监控观察:使用Actuator端点观察应用状态
- 性能测试:对比缓存前后的性能差异
- 日志分析:学会查看和分析应用日志
- 问题排查:遇到问题时学会使用监控工具定位