ApplicationEvent事件
Spring Boot 事件处理完整实例代码
本文将通过一个完整的用户注册示例,详细展示Spring Boot事件处理机制的各个方面,包括事件定义、发布、监听、异步处理、事务支持和异常处理等核心概念。
1. 事件流程图
2. 事件处理失败机制详解
在Spring Boot事件处理中,当事件发布后处理失败时,会根据不同的监听器类型产生不同的影响。理解这些失败机制对于设计健壮的事件驱动架构至关重要。
2.1 同步监听器处理失败
2.1.1 @EventListener (同步)
@EventListener
public void handleUserRegistered(UserRegisteredEvent event) {
// 如果这里抛出异常
throw new RuntimeException("邮件发送失败");
}
失败影响:
- ❌ 异常会传播到事件发布者
- ❌ 整个事务会回滚(如果在事务中)
- ❌ 后续监听器不会执行
- ❌ 用户注册操作失败
2.1.2 ApplicationListener (同步)
@Component
public class UserListener implements ApplicationListener<UserRegisteredEvent> {
@Override
public void onApplicationEvent(UserRegisteredEvent event) {
// 异常同样会传播
throw new RuntimeException("审计日志记录失败");
}
}
失败影响: 与@EventListener相同,异常会中断整个流程
2.2 异步监听器处理失败
2.2.1 @Async + @EventListener
@EventListener
@Async
public void handleUserRegisteredAsync(UserRegisteredEvent event) {
// 异步处理中的异常
throw new RuntimeException("统计分析失败");
}
失败影响:
- ✅ 异常不会传播到事件发布者
- ✅ 主流程继续执行
- ✅ 用户注册成功
- ⚠️ 异常被AsyncUncaughtExceptionHandler处理
2.2.2 异步异常处理配置
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (throwable, method, objects) -> {
logger.error("异步事件处理失败 - 方法: {}, 参数: {}",
method.getName(), objects, throwable);
// 可以在这里进行补偿处理
// 比如:重试、记录失败日志、发送告警等
handleAsyncFailure(throwable, method, objects);
};
}
private void handleAsyncFailure(Throwable throwable, Method method, Object[] objects) {
// 补偿处理逻辑
if (objects.length > 0 && objects[0] instanceof UserRegisteredEvent) {
UserRegisteredEvent event = (UserRegisteredEvent) objects[0];
// 加入重试队列或发送告警
retryService.addToRetryQueue(event, method.getName(), throwable);
}
}
}
2.3 事务监听器处理失败
2.3.1 @TransactionalEventListener
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleAfterCommit(UserRegisteredEvent event) {
throw new RuntimeException("缓存更新失败");
}
失败影响:
- ✅ 主事务已经提交,不会回滚
- ❌ 异常会被记录,但不影响主流程
- ⚠️ 需要手动处理补偿逻辑
2.4 实际场景示例
2.4.1 用户注册完整流程
@Service
@Transactional
public class UserService {
public User registerUser(String username, String email) {
try {
// 1. 保存用户到数据库
User user = saveUser(username, email);
// 2. 发布事件
UserRegisteredEvent event = new UserRegisteredEvent(this, user);
eventPublisher.publishEvent(event);
return user; // 如果同步监听器失败,这里不会执行到
} catch (Exception e) {
logger.error("用户注册失败", e);
throw e; // 事务回滚
}
}
}
2.4.2 不同监听器的失败场景
点击展开:场景1 - 邮件发送失败(同步,关键业务)
@EventListener
@Order(1)
public void sendWelcomeEmail(UserRegisteredEvent event) {
try {
emailService.sendEmail(event.getUser().getEmail());
logger.info("欢迎邮件发送成功");
} catch (Exception e) {
logger.error("邮件发送失败", e);
// 如果邮件发送是关键业务,重新抛出异常使整个注册失败
throw new BusinessException("用户注册失败:无法发送欢迎邮件", e);
}
}
结果: 用户注册失败,数据库事务回滚
点击展开:场景2 - 统计更新失败(异步,非关键业务)
@EventListener
@Async
@Order(2)
public void updateStatistics(UserRegisteredEvent event) {
try {
statisticsService.updateUserCount();
logger.info("用户统计更新成功");
} catch (Exception e) {
logger.error("统计更新失败", e);
// 异步处理,异常不会影响主流程
// 可以加入重试队列
retryQueue.add(new StatisticsRetryTask(event));
}
}
结果: 用户注册成功,统计更新失败但不影响主业务
点击展开:场景3 - 缓存更新失败(事务后处理)
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void updateCache(UserRegisteredEvent event) {
try {
cacheService.updateUserCache(event.getUser());
logger.info("用户缓存更新成功");
} catch (Exception e) {
logger.error("缓存更新失败", e);
// 主事务已提交,需要补偿处理
handleCacheUpdateFailure(event.getUser(), e);
}
}
private void handleCacheUpdateFailure(User user, Exception e) {
// 补偿策略
// 1. 记录失败日志
failureLogService.logCacheFailure(user.getId(), e);
// 2. 加入重试队列
cacheRetryQueue.add(new CacheUpdateTask(user));
// 3. 发送告警
alertService.sendCacheFailureAlert(user.getId(), e.getMessage());
}
结果: 用户注册成功,缓存更新失败需要补偿处理
2.5 最佳实践建议
2.5.1 异常处理策略
@EventListener
public void handleUserRegistered(UserRegisteredEvent event) {
try {
// 业务处理逻辑
emailService.sendWelcomeEmail(event.getUser());
} catch (Exception e) {
logger.error("发送欢迎邮件失败: {}", event.getUser().getEmail(), e);
// 根据业务需求决定是否重新抛出异常
if (isEmailCritical()) {
// 如果是关键流程,重新抛出异常使整个操作失败
throw new BusinessException("关键业务处理失败", e);
} else {
// 如果是非关键流程,记录日志并进行补偿处理
handleEmailFailure(event.getUser(), e);
}
}
}
private void handleEmailFailure(User user, Exception e) {
// 补偿处理
emailRetryService.scheduleRetry(user.getEmail(), e);
notificationService.notifyAdminOfEmailFailure(user, e);
}
2.5.2 监听器分类处理
// 关键业务逻辑 - 同步处理,失败则整体失败
@EventListener
@Order(1)
public void criticalBusinessLogic(UserRegisteredEvent event) {
try {
// 必须成功的业务逻辑
criticalService.process(event.getUser());
} catch (Exception e) {
throw new BusinessException("关键业务处理失败", e);
}
}
// 非关键业务逻辑 - 异步处理,失败不影响主流程
@EventListener
@Async
@Order(2)
public void nonCriticalBusinessLogic(UserRegisteredEvent event) {
try {
// 可以失败的业务逻辑
analyticsService.updateUserAnalytics(event.getUser());
} catch (Exception e) {
logger.warn("非关键业务处理失败", e);
// 加入重试队列或忽略
}
}
// 数据一致性要求 - 事务后处理
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void dataConsistencyLogic(UserRegisteredEvent event) {
try {
// 需要在事务提交后执行的逻辑
searchIndexService.indexUser(event.getUser());
} catch (Exception e) {
// 需要补偿处理
handleIndexFailure(event.getUser(), e);
}
}
2.5.3 补偿机制实现
@Component
public class EventFailureHandler {
private final RetryService retryService;
private final AlertService alertService;
@EventListener
public void handleEvent(UserRegisteredEvent event) {
try {
// 正常处理逻辑
processEvent(event);
} catch (Exception e) {
handleFailure(event, e);
}
}
private void handleFailure(UserRegisteredEvent event, Exception e) {
// 1. 记录失败信息
logFailure(event, e);
// 2. 根据异常类型决定处理策略
if (isRetryableException(e)) {
// 可重试异常,加入重试队列
retryService.addToRetryQueue(event, e);
} else {
// 不可重试异常,发送告警
alertService.sendAlert("事件处理失败", event, e);
}
}
@Scheduled(fixedDelay = 60000) // 每分钟重试一次
public void retryFailedEvents() {
List<RetryTask> tasks = retryService.getRetryTasks();
for (RetryTask task : tasks) {
try {
retryEventProcessing(task);
retryService.markAsSuccess(task);
} catch (Exception e) {
retryService.incrementRetryCount(task);
if (task.getRetryCount() >= MAX_RETRY_COUNT) {
alertService.sendAlert("重试次数超限", task, e);
retryService.markAsFailed(task);
}
}
}
}
}
2.6 失败处理总结
监听器类型 | 异常影响 | 事务影响 | 建议用途 | 失败处理策略 |
---|---|---|---|---|
同步监听器 | 传播到发布者,中断流程 | 导致事务回滚 | 关键业务逻辑 | 谨慎处理异常,必要时抛出 |
异步监听器 | 不影响主流程 | 不影响主事务 | 非关键业务逻辑 | 配置异常处理器,实现重试机制 |
事务监听器 | 不影响已提交事务 | 主事务已提交 | 数据一致性处理 | 实现补偿机制,确保最终一致性 |
核心原则:
- 🔴 关键流程用同步:必须成功的业务逻辑,失败时整体回滚
- 🟡 非关键流程用异步:可以容忍失败的操作,实现优雅降级
- 🔵 数据一致性用事务监听器:确保在事务确定后执行,实现最终一致性
- ⚪ 完善的异常处理和补偿机制:确保系统的健壮性和可恢复性
3. 项目结构
src/main/java/com/example/
├── EventDemoApplication.java # 主应用类
├── config/ # 配置类
│ ├── AsyncConfig.java # 异步配置
│ └── EventConfig.java # 事件配置
├── controller/ # 控制器
│ └── UserController.java # 用户控制器
├── entity/ # 实体类
│ └── User.java # 用户实体
├── event/ # 事件类
│ └── UserRegisteredEvent.java # 用户注册事件
├── listener/ # 事件监听器
│ ├── UserEventHandler.java # @EventListener监听器
│ ├── AuditLogListener.java # ApplicationListener监听器
│ └── TransactionalUserEventListener.java # 事务监听器
└── service/ # 服务类
├── UserService.java # 用户服务(事件发布者)
├── EmailService.java # 邮件服务
├── NotificationService.java # 通知服务
├── AuditService.java # 审计服务
├── CacheService.java # 缓存服务
└── SearchIndexService.java # 搜索索引服务
4. 核心代码实现
3.1 事件类定义
点击展开:UserRegisteredEvent.java - 用户注册事件
package com.example.event;
import org.springframework.context.ApplicationEvent;
import java.time.LocalDateTime;
/**
* 用户注册事件
*/
public class UserRegisteredEvent extends ApplicationEvent {
private final User user;
private final LocalDateTime registeredTime;
private final String registrationSource;
public UserRegisteredEvent(Object source, User user, String registrationSource) {
super(source);
this.user = user;
this.registeredTime = LocalDateTime.now();
this.registrationSource = registrationSource;
}
// Getters
public User getUser() {
return user;
}
public LocalDateTime getRegisteredTime() {
return registeredTime;
}
public String getRegistrationSource() {
return registrationSource;
}
@Override
public String toString() {
return "UserRegisteredEvent{" +
"user=" + user +
", registeredTime=" + registeredTime +
", registrationSource='" + registrationSource + '\'' +
'}';
}
}
点击展开:User.java - 用户实体类
package com.example.entity;
/**
* 用户实体
*/
public class User {
private Long id;
private String username;
private String email;
private boolean vip;
private String phone;
// 构造函数
public User() {}
public User(Long id, String username, String email, boolean vip, String phone) {
this.id = id;
this.username = username;
this.email = email;
this.vip = vip;
this.phone = phone;
}
// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public boolean isVip() { return vip; }
public void setVip(boolean vip) { this.vip = vip; }
public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", email='" + email + '\'' +
", vip=" + vip +
", phone='" + phone + '\'' +
'}';
}
}
3.2 事件发布者
点击展开:UserService.java - 用户服务(事件发布者)
package com.example.service;
import com.example.entity.User;
import com.example.event.UserRegisteredEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* 用户服务 - 事件发布者
*/
@Service
public class UserService {
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
@Autowired
private ApplicationEventPublisher eventPublisher;
/**
* 用户注册方法
*/
@Transactional
public User registerUser(String username, String email, String phone, boolean isVip) {
logger.info("开始注册用户: username={}, email={}", username, email);
try {
// 1. 创建用户对象
User user = new User();
user.setId(System.currentTimeMillis()); // 简单的ID生成
user.setUsername(username);
user.setEmail(email);
user.setPhone(phone);
user.setVip(isVip);
// 2. 保存用户到数据库(模拟)
saveUserToDatabase(user);
// 3. 发布用户注册事件
UserRegisteredEvent event = new UserRegisteredEvent(this, user, "WEB");
logger.info("发布用户注册事件: {}", event);
eventPublisher.publishEvent(event);
logger.info("用户注册成功: {}", user);
return user;
} catch (Exception e) {
logger.error("用户注册失败", e);
throw new RuntimeException("用户注册失败", e);
}
}
/**
* 批量注册用户
*/
@Transactional
public void batchRegisterUsers(java.util.List<User> users) {
logger.info("开始批量注册用户,数量: {}", users.size());
for (User user : users) {
// 保存用户
saveUserToDatabase(user);
// 发布事件
UserRegisteredEvent event = new UserRegisteredEvent(this, user, "BATCH");
eventPublisher.publishEvent(event);
}
logger.info("批量注册用户完成");
}
/**
* 模拟保存用户到数据库
*/
private void saveUserToDatabase(User user) {
// 模拟数据库操作
logger.debug("保存用户到数据库: {}", user);
// 模拟可能的数据库异常
if (user.getUsername().equals("error")) {
throw new RuntimeException("数据库保存失败");
}
}
}
3.3 事件监听器
点击展开:UserEventHandler.java - @EventListener注解监听器
package com.example.listener;
import com.example.event.UserRegisteredEvent;
import com.example.service.EmailService;
import com.example.service.NotificationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* 用户事件处理器 - 使用@EventListener注解
*/
@Component
public class UserEventHandler {
private static final Logger logger = LoggerFactory.getLogger(UserEventHandler.class);
@Autowired
private EmailService emailService;
@Autowired
private NotificationService notificationService;
/**
* 处理用户注册事件 - 发送欢迎邮件
*/
@EventListener
@Order(1) // 优先级最高
public void handleUserRegistered(UserRegisteredEvent event) {
logger.info("处理用户注册事件 - 发送欢迎邮件: {}", event.getUser().getEmail());
try {
// 发送欢迎邮件
emailService.sendWelcomeEmail(event.getUser());
logger.info("欢迎邮件发送成功: {}", event.getUser().getEmail());
} catch (Exception e) {
logger.error("发送欢迎邮件失败: " + event.getUser().getEmail(), e);
// 注意:同步监听器的异常会传播到事件发布者
}
}
/**
* 处理VIP用户注册 - 条件监听器
*/
@EventListener(condition = "#event.user.vip == true")
@Order(2)
public void handleVipUserRegistered(UserRegisteredEvent event) {
logger.info("处理VIP用户注册事件: {}", event.getUser().getUsername());
try {
// VIP用户特殊处理
notificationService.sendVipWelcomeMessage(event.getUser());
// 赠送VIP礼品
giveVipGifts(event.getUser());
logger.info("VIP用户注册处理完成: {}", event.getUser().getUsername());
} catch (Exception e) {
logger.error("VIP用户注册处理失败: " + event.getUser().getUsername(), e);
}
}
/**
* 异步处理用户注册 - 统计分析
*/
@EventListener
@Async
@Order(3)
public void handleUserRegisteredAsync(UserRegisteredEvent event) {
logger.info("异步处理用户注册事件 - 统计分析: {}", event.getUser().getId());
try {
// 模拟耗时的统计分析操作
Thread.sleep(2000);
// 更新用户统计
updateUserStatistics(event.getUser());
// 推荐系统处理
processRecommendations(event.getUser());
logger.info("用户注册统计分析完成: {}", event.getUser().getId());
} catch (Exception e) {
logger.error("用户注册统计分析失败: " + event.getUser().getId(), e);
// 异步监听器的异常不会传播到事件发布者
}
}
/**
* 处理来自特定来源的注册
*/
@EventListener(condition = "#event.registrationSource == 'BATCH'")
public void handleBatchRegistration(UserRegisteredEvent event) {
logger.info("处理批量注册事件: {}", event.getUser().getUsername());
// 批量注册的特殊处理逻辑
// 例如:不发送单独的欢迎邮件,而是汇总发送
}
private void giveVipGifts(com.example.entity.User user) {
logger.info("为VIP用户赠送礼品: {}", user.getUsername());
// 实现VIP礼品逻辑
}
private void updateUserStatistics(com.example.entity.User user) {
logger.info("更新用户统计信息: {}", user.getId());
// 实现统计更新逻辑
}
private void processRecommendations(com.example.entity.User user) {
logger.info("处理用户推荐: {}", user.getId());
// 实现推荐系统逻辑
}
}
点击展开:AuditLogListener.java - ApplicationListener接口监听器
package com.example.listener;
import com.example.event.UserRegisteredEvent;
import com.example.service.AuditService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
* 审计日志监听器 - 实现ApplicationListener接口
*/
@Component
public class AuditLogListener implements ApplicationListener<UserRegisteredEvent> {
private static final Logger logger = LoggerFactory.getLogger(AuditLogListener.class);
@Autowired
private AuditService auditService;
@Override
public void onApplicationEvent(UserRegisteredEvent event) {
logger.info("记录用户注册审计日志: {}", event.getUser().getId());
try {
// 记录审计日志
auditService.logUserRegistration(
event.getUser().getId(),
event.getUser().getUsername(),
event.getRegisteredTime(),
event.getRegistrationSource()
);
logger.info("用户注册审计日志记录成功: {}", event.getUser().getId());
} catch (Exception e) {
logger.error("记录用户注册审计日志失败: " + event.getUser().getId(), e);
}
}
}
点击展开:TransactionalUserEventListener.java - 事务监听器
package com.example.listener;
import com.example.event.UserRegisteredEvent;
import com.example.service.CacheService;
import com.example.service.SearchIndexService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
/**
* 事务监听器 - 确保在事务提交后执行
*/
@Component
public class TransactionalUserEventListener {
private static final Logger logger = LoggerFactory.getLogger(TransactionalUserEventListener.class);
@Autowired
private CacheService cacheService;
@Autowired
private SearchIndexService searchIndexService;
/**
* 事务提交后处理 - 更新缓存
*/
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleAfterCommit(UserRegisteredEvent event) {
logger.info("事务提交后处理用户注册事件: {}", event.getUser().getId());
try {
// 更新缓存
cacheService.updateUserCache(event.getUser());
// 更新搜索索引
searchIndexService.indexUser(event.getUser());
logger.info("事务提交后处理完成: {}", event.getUser().getId());
} catch (Exception e) {
logger.error("事务提交后处理失败: " + event.getUser().getId(), e);
}
}
/**
* 事务回滚后处理
*/
@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void handleAfterRollback(UserRegisteredEvent event) {
logger.warn("用户注册事务回滚,清理相关数据: {}", event.getUser().getId());
try {
// 清理可能已经创建的相关数据
cleanupUserData(event.getUser());
} catch (Exception e) {
logger.error("事务回滚后清理失败: " + event.getUser().getId(), e);
}
}
/**
* 事务完成后处理(无论提交还是回滚)
*/
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)
public void handleAfterCompletion(UserRegisteredEvent event) {
logger.info("用户注册事务完成: {}", event.getUser().getId());
// 记录事务完成日志
// 清理临时资源等
}
private void cleanupUserData(com.example.entity.User user) {
logger.info("清理用户相关数据: {}", user.getId());
// 实现数据清理逻辑
}
}
3.4 支持服务类
点击展开:EmailService.java - 邮件服务
package com.example.service;
import com.example.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
/**
* 邮件服务
*/
@Service
public class EmailService {
private static final Logger logger = LoggerFactory.getLogger(EmailService.class);
/**
* 发送欢迎邮件
*/
public void sendWelcomeEmail(User user) {
logger.info("发送欢迎邮件给用户: {}", user.getEmail());
// 模拟邮件发送
try {
Thread.sleep(100); // 模拟网络延迟
String emailContent = buildWelcomeEmailContent(user);
// 实际的邮件发送逻辑
sendEmail(user.getEmail(), "欢迎注册", emailContent);
logger.info("欢迎邮件发送成功: {}", user.getEmail());
} catch (Exception e) {
logger.error("发送欢迎邮件失败: " + user.getEmail(), e);
throw new RuntimeException("邮件发送失败", e);
}
}
private String buildWelcomeEmailContent(User user) {
return String.format(
"亲爱的 %s,\n\n欢迎注册我们的服务!\n\n您的用户ID是:%d\n\n祝您使用愉快!",
user.getUsername(), user.getId()
);
}
private void sendEmail(String to, String subject, String content) {
// 实际的邮件发送实现
logger.debug("发送邮件 - 收件人: {}, 主题: {}", to, subject);
}
}
点击展开:NotificationService.java - 通知服务
package com.example.service;
import com.example.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
/**
* 通知服务
*/
@Service
public class NotificationService {
private static final Logger logger = LoggerFactory.getLogger(NotificationService.class);
/**
* 发送VIP欢迎消息
*/
public void sendVipWelcomeMessage(User user) {
logger.info("发送VIP欢迎消息给用户: {}", user.getUsername());
try {
// 发送短信通知
sendSmsNotification(user.getPhone(), buildVipWelcomeMessage(user));
// 发送App推送
sendAppPushNotification(user.getId(), "VIP欢迎", "恭喜您成为VIP用户!");
logger.info("VIP欢迎消息发送成功: {}", user.getUsername());
} catch (Exception e) {
logger.error("发送VIP欢迎消息失败: " + user.getUsername(), e);
}
}
private String buildVipWelcomeMessage(User user) {
return String.format("尊敬的VIP用户 %s,欢迎您!享受专属VIP服务。", user.getUsername());
}
private void sendSmsNotification(String phone, String message) {
logger.debug("发送短信通知 - 手机号: {}, 内容: {}", phone, message);
// 实际的短信发送实现
}
private void sendAppPushNotification(Long userId, String title, String content) {
logger.debug("发送App推送 - 用户ID: {}, 标题: {}", userId, title);
// 实际的App推送实现
}
}
点击展开:AuditService.java - 审计服务
package com.example.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
/**
* 审计服务
*/
@Service
public class AuditService {
private static final Logger logger = LoggerFactory.getLogger(AuditService.class);
/**
* 记录用户注册审计日志
*/
public void logUserRegistration(Long userId, String username,
LocalDateTime registeredTime, String source) {
logger.info("记录用户注册审计日志 - 用户ID: {}, 用户名: {}, 注册时间: {}, 来源: {}",
userId, username, registeredTime, source);
try {
// 保存到审计日志表
saveAuditLog("USER_REGISTRATION", userId, username, registeredTime, source);
logger.debug("用户注册审计日志保存成功");
} catch (Exception e) {
logger.error("保存用户注册审计日志失败", e);
}
}
private void saveAuditLog(String action, Long userId, String username,
LocalDateTime timestamp, String source) {
// 实际的审计日志保存实现
logger.debug("保存审计日志 - 操作: {}, 用户: {}", action, username);
}
}
点击展开:CacheService.java - 缓存服务
package com.example.service;
import com.example.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
/**
* 缓存服务
*/
@Service
public class CacheService {
private static final Logger logger = LoggerFactory.getLogger(CacheService.class);
/**
* 更新用户缓存
*/
public void updateUserCache(User user) {
logger.info("更新用户缓存: {}", user.getId());
try {
// 更新Redis缓存
updateRedisCache("user:" + user.getId(), user);
// 更新本地缓存
updateLocalCache(user);
logger.debug("用户缓存更新成功: {}", user.getId());
} catch (Exception e) {
logger.error("更新用户缓存失败: " + user.getId(), e);
}
}
private void updateRedisCache(String key, User user) {
logger.debug("更新Redis缓存 - Key: {}", key);
// 实际的Redis缓存更新实现
}
private void updateLocalCache(User user) {
logger.debug("更新本地缓存 - 用户: {}", user.getId());
// 实际的本地缓存更新实现
}
}
点击展开:SearchIndexService.java - 搜索索引服务
package com.example.service;
import com.example.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
/**
* 搜索索引服务
*/
@Service
public class SearchIndexService {
private static final Logger logger = LoggerFactory.getLogger(SearchIndexService.class);
/**
* 为用户建立搜索索引
*/
public void indexUser(User user) {
logger.info("为用户建立搜索索引: {}", user.getId());
try {
// 构建索引文档
String indexDocument = buildUserIndexDocument(user);
// 提交到Elasticsearch
submitToElasticsearch("users", user.getId().toString(), indexDocument);
logger.debug("用户搜索索引建立成功: {}", user.getId());
} catch (Exception e) {
logger.error("建立用户搜索索引失败: " + user.getId(), e);
}
}
private String buildUserIndexDocument(User user) {
// 构建Elasticsearch文档
return String.format(
"{\"id\":%d,\"username\":\"%s\",\"email\":\"%s\",\"vip\":%b}",
user.getId(), user.getUsername(), user.getEmail(), user.isVip()
);
}
private void submitToElasticsearch(String index, String id, String document) {
logger.debug("提交到Elasticsearch - 索引: {}, ID: {}", index, id);
// 实际的Elasticsearch提交实现
}
}
3.5 配置类
点击展开:AsyncConfig.java - 异步配置
package com.example.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
/**
* 异步配置
*/
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
private static final Logger logger = LoggerFactory.getLogger(AsyncConfig.class);
@Override
@Bean(name = "taskExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("EventAsync-");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.initialize();
logger.info("异步任务执行器配置完成");
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (throwable, method, objects) -> {
logger.error("异步方法执行异常 - 方法: {}, 参数: {}",
method.getName(), objects, throwable);
};
}
}
点击展开:EventConfig.java - 事件配置
package com.example.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
/**
* 事件配置
*/
@Configuration
public class EventConfig {
private static final Logger logger = LoggerFactory.getLogger(EventConfig.class);
/**
* 自定义事件多播器
*/
@Bean(name = "applicationEventMulticaster")
public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
// 设置异步任务执行器
eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
// 设置错误处理器
eventMulticaster.setErrorHandler(throwable -> {
logger.error("事件处理异常", throwable);
});
logger.info("自定义事件多播器配置完成");
return eventMulticaster;
}
}
3.6 控制器和主应用类
点击展开:UserController.java - 用户控制器
package com.example.controller;
import com.example.entity.User;
import com.example.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
/**
* 用户控制器 - 测试事件处理
*/
@RestController
@RequestMapping("/api/users")
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
@Autowired
private UserService userService;
/**
* 注册单个用户
*/
@PostMapping("/register")
public ResponseEntity<User> registerUser(@RequestBody UserRegistrationRequest request) {
logger.info("接收用户注册请求: {}", request);
try {
User user = userService.registerUser(
request.getUsername(),
request.getEmail(),
request.getPhone(),
request.isVip()
);
return ResponseEntity.ok(user);
} catch (Exception e) {
logger.error("用户注册失败", e);
return ResponseEntity.badRequest().build();
}
}
/**
* 批量注册用户
*/
@PostMapping("/batch-register")
public ResponseEntity<String> batchRegisterUsers() {
logger.info("开始批量注册用户测试");
try {
List<User> users = Arrays.asList(
new User(null, "user1", "user1@example.com", false, "13800000001"),
new User(null, "user2", "user2@example.com", true, "13800000002"),
new User(null, "user3", "user3@example.com", false, "13800000003")
);
userService.batchRegisterUsers(users);
return ResponseEntity.ok("批量注册成功");
} catch (Exception e) {
logger.error("批量注册失败", e);
return ResponseEntity.badRequest().body("批量注册失败");
}
}
/**
* 测试异常情况
*/
@PostMapping("/register-error")
public ResponseEntity<String> registerErrorUser() {
logger.info("测试异常用户注册");
try {
userService.registerUser("error", "error@example.com", "13800000000", false);
return ResponseEntity.ok("注册成功");
} catch (Exception e) {
logger.error("预期的注册异常", e);
return ResponseEntity.badRequest().body("注册失败: " + e.getMessage());
}
}
/**
* 用户注册请求DTO
*/
public static class UserRegistrationRequest {
private String username;
private String email;
private String phone;
private boolean vip;
// Getters and Setters
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }
public boolean isVip() { return vip; }
public void setVip(boolean vip) { this.vip = vip; }
@Override
public String toString() {
return "UserRegistrationRequest{" +
"username='" + username + '\'' +
", email='" + email + '\'' +
", phone='" + phone + '\'' +
", vip=" + vip +
'}';
}
}
}
点击展开:EventDemoApplication.java - 主应用类
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* Spring Boot 事件处理示例应用
*/
@SpringBootApplication
@EnableTransactionManagement
public class EventDemoApplication {
public static void main(String[] args) {
SpringApplication.run(EventDemoApplication.class, args);
System.out.println("Spring Boot 事件处理示例应用启动成功!");
System.out.println("测试URL:");
System.out.println("POST http://localhost:8080/api/users/register");
System.out.println("POST http://localhost:8080/api/users/batch-register");
System.out.println("POST http://localhost:8080/api/users/register-error");
}
}
3.7 配置文件和测试
点击展开:application.yml - 配置文件
server:
port: 8080
spring:
application:
name: spring-boot-event-demo
logging:
level:
com.example: DEBUG
org.springframework.context.event: DEBUG
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
# 自定义配置
app:
event:
async:
core-pool-size: 5
max-pool-size: 10
queue-capacity: 100
点击展开:EventProcessingTest.java - 测试用例
package com.example;
import com.example.entity.User;
import com.example.event.UserRegisteredEvent;
import com.example.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.junit.jupiter.api.Assertions.*;
/**
* 事件处理测试
*/
@SpringBootTest
@SpringJUnitConfig
public class EventProcessingTest {
@Autowired
private UserService userService;
@Autowired
private ApplicationEventPublisher eventPublisher;
@Test
public void testUserRegistration() {
// 测试用户注册和事件处理
User user = userService.registerUser("testuser", "test@example.com", "13800000000", false);
assertNotNull(user);
assertEquals("testuser", user.getUsername());
assertEquals("test@example.com", user.getEmail());
}
@Test
public void testVipUserRegistration() {
// 测试VIP用户注册
User vipUser = userService.registerUser("vipuser", "vip@example.com", "13800000001", true);
assertNotNull(vipUser);
assertTrue(vipUser.isVip());
}
@Test
public void testDirectEventPublishing() {
// 直接发布事件测试
User user = new User(999L, "directuser", "direct@example.com", false, "13800000002");
UserRegisteredEvent event = new UserRegisteredEvent(this, user, "TEST");
// 发布事件
eventPublisher.publishEvent(event);
// 验证事件已发布(通过日志观察)
assertNotNull(event);
}
}
4. 运行和测试
4.1 启动应用
# 编译和运行
mvn clean compile
mvn spring-boot:run
# 或者打包运行
mvn clean package
java -jar target/spring-boot-event-demo.jar
4.2 API测试
点击展开:API测试命令
# 注册普通用户
curl -X POST http://localhost:8080/api/users/register \
-H "Content-Type: application/json" \
-d '{
"username": "john",
"email": "john@example.com",
"phone": "13800000001",
"vip": false
}'
# 注册VIP用户
curl -X POST http://localhost:8080/api/users/register \
-H "Content-Type: application/json" \
-d '{
"username": "vipjohn",
"email": "vipjohn@example.com",
"phone": "13800000002",
"vip": true
}'
# 批量注册测试
curl -X POST http://localhost:8080/api/users/batch-register
# 异常情况测试
curl -X POST http://localhost:8080/api/users/register-error
4.3 日志观察
运行应用后,观察控制台日志输出,可以看到:
- 事件发布日志:显示事件何时被发布
- 监听器处理日志:各个监听器的执行顺序和结果
- 同步vs异步:同步监听器立即执行,异步监听器在后台执行
- 事务监听器:在事务提交后才执行
- 异常处理:同步监听器异常会影响主流程,异步不会
5. 核心特性总结
5.1 事件处理类型
监听器类型 | 特点 | 使用场景 |
---|---|---|
@EventListener | 简单易用,支持条件监听 | 大部分业务场景 |
ApplicationListener | 传统方式,类型安全 | 需要类型安全的场景 |
@TransactionalEventListener | 事务感知,确保数据一致性 | 需要事务保证的场景 |
@Async + @EventListener | 异步处理,不阻塞主流程 | 耗时操作,如统计分析 |
5.2 设计模式应用
- 观察者模式:事件发布-订阅机制
- 模板方法模式:ApplicationListener接口
- 策略模式:不同类型的事件处理策略
- 责任链模式:多个监听器按顺序处理
5.3 最佳实践
- 事件设计:事件应该是不可变对象,包含足够的上下文信息
- 监听器设计:保持监听器方法简单,耗时操作使用@Async
- 异常处理:同步监听器要处理好异常,异步监听器配置ErrorHandler
- 性能优化:避免在监听器中执行阻塞操作,使用条件监听减少无效调用
这个完整的示例展示了Spring Boot事件处理机制的所有核心概念和最佳实践,可以作为实际项目中事件驱动架构设计的参考模板。