Spring事件机制详解

Spring事件机制详解:从原理到实战

前言

Spring事件机制是基于观察者模式实现的一套事件驱动架构,它允许应用程序中的不同组件之间进行松耦合的通信。通过事件机制,我们可以将业务逻辑解耦,提高代码的可维护性和可扩展性。本文将深入讲解Spring事件机制的核心概念、实现原理和实战应用。

一、事件机制概述

1.1 什么是事件驱动

事件驱动编程是一种编程范式,程序的执行流程由事件来决定。当某个事件发生时,会触发相应的事件处理器来执行特定的操作。

vbnet 复制代码
传统调用 vs 事件驱动
┌─────────────────────────────────────────┐
│  传统调用(紧耦合)                      │
│  ┌──────────┐                           │
│  │UserService│                          │
│  └─────┬────┘                           │
│        │ 直接调用                        │
│        ├─────────> EmailService         │
│        ├─────────> SmsService           │
│        ├─────────> CouponService        │
│        └─────────> LogService           │
│                                          │
│  问题:UserService需要知道所有依赖       │
├─────────────────────────────────────────┤
│  事件驱动(松耦合)                      │
│  ┌──────────┐        Event              │
│  │UserService├───────> EventBus         │
│  └──────────┘            │               │
│                          │               │
│         ┌────────────────┼────────────┐ │
│         ▼                ▼            ▼  │
│    EmailService   SmsService  CouponService
│                                          │
│  优势:各组件独立,互不影响               │
└─────────────────────────────────────────┘

1.2 Spring事件机制核心组件

复制代码
Spring事件机制核心组件
┌─────────────────────────────────────────┐
│  ApplicationEvent(事件)                │
│  - Spring事件的基类                      │
│  - 携带事件相关数据                      │
├─────────────────────────────────────────┤
│  ApplicationListener(监听器)           │
│  - 事件监听接口                          │
│  - 处理特定类型的事件                    │
├─────────────────────────────────────────┤
│  ApplicationEventPublisher(发布器)     │
│  - 事件发布接口                          │
│  - ApplicationContext实现了该接口        │
├─────────────────────────────────────────┤
│  ApplicationEventMulticaster(广播器)   │
│  - 事件广播器                            │
│  - 负责将事件分发给所有监听器            │
└─────────────────────────────────────────┘

1.3 事件机制工作流程

scss 复制代码
事件发布与监听流程
┌──────────────┐
│  发布事件     │
│  publishEvent│
└──────┬───────┘
       │
       ▼
┌─────────────────────────────┐
│  ApplicationEventPublisher  │
└──────┬──────────────────────┘
       │
       ▼
┌─────────────────────────────┐
│ ApplicationEventMulticaster │
│ (事件广播器)               │
└──────┬──────────────────────┘
       │
       ├──────────────────────────┐
       │                          │
       ▼                          ▼
┌─────────────┐          ┌─────────────┐
│  Listener1  │          │  Listener2  │
│  onEvent()  │          │  onEvent()  │
└─────────────┘          └─────────────┘

二、Spring事件基础

2.1 创建自定义事件

java 复制代码
/**
 * 自定义事件 - 用户注册事件
 */
public class UserRegisterEvent extends ApplicationEvent {

    private User user;
    private String registerIp;
    private LocalDateTime registerTime;

    public UserRegisterEvent(Object source, User user, String registerIp) {
        super(source);
        this.user = user;
        this.registerIp = registerIp;
        this.registerTime = LocalDateTime.now();
    }

    public User getUser() {
        return user;
    }

    public String getRegisterIp() {
        return registerIp;
    }

    public LocalDateTime getRegisterTime() {
        return registerTime;
    }
}

/**
 * 用户实体
 */
@Data
@AllArgsConstructor
public class User {
    private Long id;
    private String username;
    private String email;
    private String phone;
}

2.2 创建事件监听器

方式一:实现ApplicationListener接口
java 复制代码
/**
 * 方式1:实现ApplicationListener接口
 */
@Component
public class UserRegisterListener implements ApplicationListener<UserRegisterEvent> {

    private static final Logger log = LoggerFactory.getLogger(UserRegisterListener.class);

    @Override
    public void onApplicationEvent(UserRegisterEvent event) {
        User user = event.getUser();
        log.info("用户注册监听器收到事件: 用户[{}]于{}注册,IP: {}",
                user.getUsername(),
                event.getRegisterTime(),
                event.getRegisterIp());

        // 处理用户注册后的业务逻辑
        sendWelcomeEmail(user);
    }

    private void sendWelcomeEmail(User user) {
        log.info("发送欢迎邮件给: {}", user.getEmail());
    }
}
方式二:使用@EventListener注解
java 复制代码
/**
 * 方式2:使用@EventListener注解(推荐)
 */
@Component
@Slf4j
public class UserRegisterEventHandler {

    /**
     * 发送欢迎邮件
     */
    @EventListener
    public void handleWelcomeEmail(UserRegisterEvent event) {
        User user = event.getUser();
        log.info("发送欢迎邮件给: {}", user.getEmail());

        // 模拟发送邮件
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 赠送新人优惠券
     */
    @EventListener
    public void handleNewUserCoupon(UserRegisterEvent event) {
        User user = event.getUser();
        log.info("为新用户[{}]赠送优惠券", user.getUsername());

        // 模拟赠送优惠券
        grantCoupon(user);
    }

    /**
     * 记录注册日志
     */
    @EventListener
    public void handleRegisterLog(UserRegisterEvent event) {
        User user = event.getUser();
        log.info("记录用户注册日志: 用户[{}], IP[{}], 时间[{}]",
                user.getUsername(),
                event.getRegisterIp(),
                event.getRegisterTime());
    }

    private void grantCoupon(User user) {
        // 优惠券发放逻辑
    }
}

2.3 发布事件

java 复制代码
/**
 * 用户服务 - 发布事件
 */
@Service
@Slf4j
public class UserService {

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Autowired
    private UserDao userDao;

    /**
     * 用户注册
     */
    public void register(User user, String ip) {
        // 1. 保存用户
        userDao.save(user);
        log.info("用户保存成功: {}", user.getUsername());

        // 2. 发布用户注册事件
        UserRegisterEvent event = new UserRegisterEvent(this, user, ip);
        eventPublisher.publishEvent(event);
        log.info("用户注册事件已发布");

        // 3. 后续逻辑不需要关心事件的处理
    }
}

2.4 完整示例

java 复制代码
/**
 * 测试类
 */
@SpringBootTest
public class EventTest {

    @Autowired
    private UserService userService;

    @Test
    public void testUserRegister() {
        User user = new User(1L, "zhangsan", "zhangsan@example.com", "13800138000");
        userService.register(user, "192.168.1.100");
    }
}

/**
 * 控制台输出:
 * 用户保存成功: zhangsan
 * 用户注册事件已发布
 * 发送欢迎邮件给: zhangsan@example.com
 * 为新用户[zhangsan]赠送优惠券
 * 记录用户注册日志: 用户[zhangsan], IP[192.168.1.100], 时间[2024-01-01T10:00:00]
 */

三、高级特性

3.1 条件监听

java 复制代码
/**
 * 条件监听 - 使用SpEL表达式
 */
@Component
@Slf4j
public class ConditionalEventListener {

    /**
     * 只处理来自北京的用户注册
     */
    @EventListener(condition = "#event.registerIp.startsWith('110')")
    public void handleBeijingUser(UserRegisterEvent event) {
        log.info("北京用户注册: {}", event.getUser().getUsername());
    }

    /**
     * 只处理邮箱为gmail的用户
     */
    @EventListener(condition = "#event.user.email.contains('gmail')")
    public void handleGmailUser(UserRegisterEvent event) {
        log.info("Gmail用户注册: {}", event.getUser().getEmail());
    }

    /**
     * 用户ID大于100的注册事件
     */
    @EventListener(condition = "#event.user.id > 100")
    public void handleVIPUser(UserRegisterEvent event) {
        log.info("VIP用户注册: {}", event.getUser().getId());
    }
}

3.2 异步事件监听

java 复制代码
/**
 * 启用异步支持
 */
@Configuration
@EnableAsync
public class AsyncConfig {

    @Bean
    public ThreadPoolTaskExecutor asyncEventExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("async-event-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

/**
 * 异步事件监听器
 */
@Component
@Slf4j
public class AsyncEventListener {

    /**
     * 异步发送欢迎邮件
     */
    @Async("asyncEventExecutor")
    @EventListener
    public void handleWelcomeEmailAsync(UserRegisterEvent event) {
        log.info("异步线程[{}]发送欢迎邮件", Thread.currentThread().getName());

        // 模拟耗时操作
        try {
            Thread.sleep(2000);
            log.info("欢迎邮件发送完成: {}", event.getUser().getEmail());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 异步发送短信通知
     */
    @Async("asyncEventExecutor")
    @EventListener
    public void handleSmsAsync(UserRegisterEvent event) {
        log.info("异步线程[{}]发送短信", Thread.currentThread().getName());

        try {
            Thread.sleep(1000);
            log.info("短信发送完成: {}", event.getUser().getPhone());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

3.3 事件监听顺序

java 复制代码
/**
 * 使用@Order控制监听器执行顺序
 */
@Component
@Slf4j
@Order(1)  // 数字越小,优先级越高
public class FirstEventListener {

    @EventListener
    public void handle(UserRegisterEvent event) {
        log.info("第一个监听器执行");
    }
}

@Component
@Slf4j
@Order(2)
public class SecondEventListener {

    @EventListener
    public void handle(UserRegisterEvent event) {
        log.info("第二个监听器执行");
    }
}

@Component
@Slf4j
@Order(3)
public class ThirdEventListener {

    @EventListener
    public void handle(UserRegisterEvent event) {
        log.info("第三个监听器执行");
    }
}

3.4 泛型事件

java 复制代码
/**
 * 泛型事件基类
 */
public class EntityEvent<T> extends ApplicationEvent {

    private T entity;
    private EventType eventType;

    public EntityEvent(Object source, T entity, EventType eventType) {
        super(source);
        this.entity = entity;
        this.eventType = eventType;
    }

    public T getEntity() {
        return entity;
    }

    public EventType getEventType() {
        return eventType;
    }

    public enum EventType {
        CREATE, UPDATE, DELETE
    }
}

/**
 * 泛型事件监听器
 */
@Component
@Slf4j
public class GenericEventListener {

    /**
     * 监听User实体事件
     */
    @EventListener
    public void handleUserEvent(EntityEvent<User> event) {
        User user = event.getEntity();
        EventType type = event.getEventType();
        log.info("User实体事件: {}, 用户: {}", type, user.getUsername());
    }

    /**
     * 监听Product实体事件
     */
    @EventListener
    public void handleProductEvent(EntityEvent<Product> event) {
        Product product = event.getEntity();
        EventType type = event.getEventType();
        log.info("Product实体事件: {}, 商品: {}", type, product.getName());
    }
}

/**
 * 使用泛型事件
 */
@Service
public class GenericEventService {

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    public void createUser(User user) {
        // 创建用户
        // ...

        // 发布创建事件
        eventPublisher.publishEvent(
            new EntityEvent<>(this, user, EntityEvent.EventType.CREATE)
        );
    }

    public void updateProduct(Product product) {
        // 更新商品
        // ...

        // 发布更新事件
        eventPublisher.publishEvent(
            new EntityEvent<>(this, product, EntityEvent.EventType.UPDATE)
        );
    }
}

3.5 事务事件监听

java 复制代码
/**
 * 事务事件监听器
 * @TransactionalEventListener可以在事务的不同阶段触发
 */
@Component
@Slf4j
public class TransactionalEventListener {

    /**
     * 事务提交后执行(默认)
     */
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void handleAfterCommit(UserRegisterEvent event) {
        log.info("事务提交后执行: {}", event.getUser().getUsername());
        // 发送通知邮件等操作
    }

    /**
     * 事务回滚后执行
     */
    @TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
    public void handleAfterRollback(UserRegisterEvent event) {
        log.info("事务回滚后执行: {}", event.getUser().getUsername());
        // 记录失败日志
    }

    /**
     * 事务完成后执行(无论提交还是回滚)
     */
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)
    public void handleAfterCompletion(UserRegisterEvent event) {
        log.info("事务完成后执行: {}", event.getUser().getUsername());
        // 清理资源
    }

    /**
     * 事务提交前执行
     */
    @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
    public void handleBeforeCommit(UserRegisterEvent event) {
        log.info("事务提交前执行: {}", event.getUser().getUsername());
        // 数据校验
    }
}

/**
 * 带事务的服务
 */
@Service
public class TransactionalUserService {

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Autowired
    private UserDao userDao;

    @Transactional
    public void registerWithTransaction(User user, String ip) {
        // 保存用户
        userDao.save(user);

        // 发布事件
        eventPublisher.publishEvent(new UserRegisterEvent(this, user, ip));

        // 如果后续代码抛出异常,事务回滚
        // 监听器的执行时机取决于@TransactionalEventListener的phase配置
    }
}

四、实战案例

4.1 案例1:订单状态变更通知

java 复制代码
/**
 * 订单状态变更事件
 */
public class OrderStatusChangeEvent extends ApplicationEvent {

    private Order order;
    private OrderStatus oldStatus;
    private OrderStatus newStatus;

    public OrderStatusChangeEvent(Object source, Order order,
                                  OrderStatus oldStatus, OrderStatus newStatus) {
        super(source);
        this.order = order;
        this.oldStatus = oldStatus;
        this.newStatus = newStatus;
    }

    public Order getOrder() { return order; }
    public OrderStatus getOldStatus() { return oldStatus; }
    public OrderStatus getNewStatus() { return newStatus; }
}

/**
 * 订单实体
 */
@Data
public class Order {
    private Long id;
    private String orderNo;
    private Long userId;
    private BigDecimal amount;
    private OrderStatus status;
}

/**
 * 订单状态枚举
 */
public enum OrderStatus {
    PENDING("待支付"),
    PAID("已支付"),
    SHIPPED("已发货"),
    COMPLETED("已完成"),
    CANCELLED("已取消");

    private String description;

    OrderStatus(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }
}

/**
 * 订单状态变更监听器
 */
@Component
@Slf4j
public class OrderStatusEventListener {

    @Autowired
    private NotificationService notificationService;

    @Autowired
    private InventoryService inventoryService;

    /**
     * 订单支付成功 - 发送通知
     */
    @EventListener(condition = "#event.newStatus.name() == 'PAID'")
    public void handleOrderPaid(OrderStatusChangeEvent event) {
        Order order = event.getOrder();
        log.info("订单已支付: {}", order.getOrderNo());

        // 发送支付成功通知
        notificationService.sendOrderPaidNotification(order);
    }

    /**
     * 订单发货 - 更新库存
     */
    @EventListener(condition = "#event.newStatus.name() == 'SHIPPED'")
    public void handleOrderShipped(OrderStatusChangeEvent event) {
        Order order = event.getOrder();
        log.info("订单已发货: {}", order.getOrderNo());

        // 扣减库存
        inventoryService.deductInventory(order);

        // 发送发货通知
        notificationService.sendShippingNotification(order);
    }

    /**
     * 订单取消 - 退款处理
     */
    @EventListener(condition = "#event.newStatus.name() == 'CANCELLED'")
    public void handleOrderCancelled(OrderStatusChangeEvent event) {
        Order order = event.getOrder();
        OrderStatus oldStatus = event.getOldStatus();
        log.info("订单已取消: {}, 原状态: {}", order.getOrderNo(), oldStatus);

        // 如果已支付,需要退款
        if (oldStatus == OrderStatus.PAID || oldStatus == OrderStatus.SHIPPED) {
            processRefund(order);
        }
    }

    /**
     * 订单完成 - 增加积分
     */
    @EventListener(condition = "#event.newStatus.name() == 'COMPLETED'")
    public void handleOrderCompleted(OrderStatusChangeEvent event) {
        Order order = event.getOrder();
        log.info("订单已完成: {}", order.getOrderNo());

        // 增加用户积分
        addUserPoints(order);

        // 请求用户评价
        notificationService.requestReview(order);
    }

    private void processRefund(Order order) {
        log.info("处理退款: 订单{}, 金额{}", order.getOrderNo(), order.getAmount());
    }

    private void addUserPoints(Order order) {
        int points = order.getAmount().intValue();
        log.info("为用户{}增加{}积分", order.getUserId(), points);
    }
}

/**
 * 订单服务
 */
@Service
@Slf4j
public class OrderService {

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Autowired
    private OrderDao orderDao;

    /**
     * 更新订单状态
     */
    @Transactional
    public void updateOrderStatus(Long orderId, OrderStatus newStatus) {
        // 查询订单
        Order order = orderDao.findById(orderId);
        OrderStatus oldStatus = order.getStatus();

        // 更新状态
        order.setStatus(newStatus);
        orderDao.update(order);

        log.info("订单状态更新: {} -> {}", oldStatus, newStatus);

        // 发布状态变更事件
        OrderStatusChangeEvent event = new OrderStatusChangeEvent(
            this, order, oldStatus, newStatus
        );
        eventPublisher.publishEvent(event);
    }
}

4.2 案例2:系统监控告警

java 复制代码
/**
 * 系统监控事件
 */
public class SystemMonitorEvent extends ApplicationEvent {

    private MonitorType type;
    private String message;
    private Map<String, Object> metrics;
    private AlertLevel level;

    public SystemMonitorEvent(Object source, MonitorType type,
                             String message, AlertLevel level) {
        super(source);
        this.type = type;
        this.message = message;
        this.level = level;
        this.metrics = new HashMap<>();
    }

    public void addMetric(String key, Object value) {
        metrics.put(key, value);
    }

    // Getters
    public MonitorType getType() { return type; }
    public String getMessage() { return message; }
    public AlertLevel getLevel() { return level; }
    public Map<String, Object> getMetrics() { return metrics; }
}

/**
 * 监控类型
 */
public enum MonitorType {
    CPU_USAGE,      // CPU使用率
    MEMORY_USAGE,   // 内存使用率
    DISK_USAGE,     // 磁盘使用率
    API_ERROR,      // API错误
    SLOW_QUERY      // 慢查询
}

/**
 * 告警级别
 */
public enum AlertLevel {
    INFO, WARNING, ERROR, CRITICAL
}

/**
 * 系统监控监听器
 */
@Component
@Slf4j
public class SystemMonitorListener {

    @Autowired
    private EmailService emailService;

    @Autowired
    private SmsService smsService;

    @Autowired
    private DingTalkService dingTalkService;

    /**
     * 严重告警 - 多渠道通知
     */
    @EventListener(condition = "#event.level.name() == 'CRITICAL'")
    public void handleCriticalAlert(SystemMonitorEvent event) {
        log.error("严重告警: {} - {}", event.getType(), event.getMessage());

        // 发送邮件
        emailService.sendAlert("严重告警", formatAlertMessage(event));

        // 发送短信
        smsService.sendAlert(formatAlertMessage(event));

        // 发送钉钉通知
        dingTalkService.sendAlert(formatAlertMessage(event));
    }

    /**
     * 错误告警 - 邮件+钉钉通知
     */
    @EventListener(condition = "#event.level.name() == 'ERROR'")
    public void handleErrorAlert(SystemMonitorEvent event) {
        log.error("错误告警: {} - {}", event.getType(), event.getMessage());

        emailService.sendAlert("错误告警", formatAlertMessage(event));
        dingTalkService.sendAlert(formatAlertMessage(event));
    }

    /**
     * 警告告警 - 钉钉通知
     */
    @EventListener(condition = "#event.level.name() == 'WARNING'")
    public void handleWarningAlert(SystemMonitorEvent event) {
        log.warn("警告告警: {} - {}", event.getType(), event.getMessage());

        dingTalkService.sendAlert(formatAlertMessage(event));
    }

    /**
     * CPU使用率告警 - 特殊处理
     */
    @EventListener(condition = "#event.type.name() == 'CPU_USAGE'")
    public void handleCpuUsageAlert(SystemMonitorEvent event) {
        log.info("CPU使用率告警: {}", event.getMessage());

        // 记录CPU使用率历史
        saveCpuUsageHistory(event);

        // 尝试自动扩容
        if (event.getLevel() == AlertLevel.CRITICAL) {
            tryAutoScale();
        }
    }

    private String formatAlertMessage(SystemMonitorEvent event) {
        StringBuilder sb = new StringBuilder();
        sb.append("告警类型: ").append(event.getType()).append("\n");
        sb.append("告警级别: ").append(event.getLevel()).append("\n");
        sb.append("告警信息: ").append(event.getMessage()).append("\n");
        sb.append("指标数据: ").append(event.getMetrics()).append("\n");
        sb.append("时间: ").append(LocalDateTime.now()).append("\n");
        return sb.toString();
    }

    private void saveCpuUsageHistory(SystemMonitorEvent event) {
        // 保存CPU使用率历史数据
    }

    private void tryAutoScale() {
        log.info("尝试自动扩容...");
        // 触发自动扩容逻辑
    }
}

/**
 * 系统监控服务
 */
@Service
@Slf4j
public class SystemMonitorService {

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    /**
     * 监控CPU使用率
     */
    @Scheduled(fixedRate = 60000)  // 每分钟检查一次
    public void monitorCpuUsage() {
        double cpuUsage = getCpuUsage();

        if (cpuUsage > 90) {
            publishAlert(MonitorType.CPU_USAGE,
                "CPU使用率过高: " + cpuUsage + "%",
                AlertLevel.CRITICAL,
                "cpuUsage", cpuUsage);
        } else if (cpuUsage > 80) {
            publishAlert(MonitorType.CPU_USAGE,
                "CPU使用率较高: " + cpuUsage + "%",
                AlertLevel.WARNING,
                "cpuUsage", cpuUsage);
        }
    }

    /**
     * 监控API错误率
     */
    public void reportApiError(String api, Exception e) {
        publishAlert(MonitorType.API_ERROR,
            "API调用失败: " + api + ", 错误: " + e.getMessage(),
            AlertLevel.ERROR,
            "api", api,
            "error", e.getMessage());
    }

    private void publishAlert(MonitorType type, String message,
                             AlertLevel level, Object... metrics) {
        SystemMonitorEvent event = new SystemMonitorEvent(this, type, message, level);

        // 添加指标数据
        for (int i = 0; i < metrics.length; i += 2) {
            event.addMetric((String) metrics[i], metrics[i + 1]);
        }

        eventPublisher.publishEvent(event);
    }

    private double getCpuUsage() {
        // 获取CPU使用率
        return Math.random() * 100;
    }
}

4.3 案例3:数据变更审计

java 复制代码
/**
 * 数据变更事件
 */
public class DataChangeEvent extends ApplicationEvent {

    private String entityType;
    private Long entityId;
    private OperationType operationType;
    private Map<String, Object> oldValues;
    private Map<String, Object> newValues;
    private String operator;

    public DataChangeEvent(Object source, String entityType, Long entityId,
                          OperationType operationType, String operator) {
        super(source);
        this.entityType = entityType;
        this.entityId = entityId;
        this.operationType = operationType;
        this.operator = operator;
        this.oldValues = new HashMap<>();
        this.newValues = new HashMap<>();
    }

    public void addChange(String field, Object oldValue, Object newValue) {
        oldValues.put(field, oldValue);
        newValues.put(field, newValue);
    }

    // Getters
    public String getEntityType() { return entityType; }
    public Long getEntityId() { return entityId; }
    public OperationType getOperationType() { return operationType; }
    public Map<String, Object> getOldValues() { return oldValues; }
    public Map<String, Object> getNewValues() { return newValues; }
    public String getOperator() { return operator; }
}

/**
 * 操作类型
 */
public enum OperationType {
    CREATE, UPDATE, DELETE
}

/**
 * 审计日志实体
 */
@Data
public class AuditLog {
    private Long id;
    private String entityType;
    private Long entityId;
    private String operationType;
    private String changes;
    private String operator;
    private LocalDateTime createTime;
}

/**
 * 数据变更审计监听器
 */
@Component
@Slf4j
public class DataChangeAuditListener {

    @Autowired
    private AuditLogService auditLogService;

    /**
     * 记录所有数据变更
     */
    @Async
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void handleDataChange(DataChangeEvent event) {
        log.info("记录数据变更审计: {} {} {}",
                event.getOperationType(),
                event.getEntityType(),
                event.getEntityId());

        // 创建审计日志
        AuditLog auditLog = new AuditLog();
        auditLog.setEntityType(event.getEntityType());
        auditLog.setEntityId(event.getEntityId());
        auditLog.setOperationType(event.getOperationType().name());
        auditLog.setOperator(event.getOperator());
        auditLog.setCreateTime(LocalDateTime.now());

        // 记录变更内容
        Map<String, Object> changes = new HashMap<>();
        changes.put("old", event.getOldValues());
        changes.put("new", event.getNewValues());
        auditLog.setChanges(JSON.toJSONString(changes));

        // 保存审计日志
        auditLogService.save(auditLog);
    }

    /**
     * 敏感数据变更 - 额外通知
     */
    @EventListener(condition = "#event.entityType == 'User' && " +
                               "#event.newValues.containsKey('role')")
    public void handleSensitiveChange(DataChangeEvent event) {
        log.warn("敏感数据变更: 用户[{}]的角色被[{}]修改",
                event.getEntityId(),
                event.getOperator());

        // 发送安全通知
        sendSecurityAlert(event);
    }

    private void sendSecurityAlert(DataChangeEvent event) {
        // 发送安全告警
    }
}

/**
 * 用户服务 - 发布数据变更事件
 */
@Service
@Slf4j
public class UserAuditService {

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Autowired
    private UserDao userDao;

    @Transactional
    public void updateUser(Long userId, User newUser, String operator) {
        // 查询旧数据
        User oldUser = userDao.findById(userId);

        // 更新数据
        userDao.update(newUser);

        // 发布数据变更事件
        DataChangeEvent event = new DataChangeEvent(
            this, "User", userId, OperationType.UPDATE, operator
        );

        // 记录变更字段
        if (!Objects.equals(oldUser.getUsername(), newUser.getUsername())) {
            event.addChange("username", oldUser.getUsername(), newUser.getUsername());
        }
        if (!Objects.equals(oldUser.getEmail(), newUser.getEmail())) {
            event.addChange("email", oldUser.getEmail(), newUser.getEmail());
        }

        eventPublisher.publishEvent(event);
    }
}

4.4 案例4:分布式事件总线

java 复制代码
/**
 * 分布式事件(通过消息队列)
 */
public class DistributedEvent implements Serializable {

    private String eventId;
    private String eventType;
    private String source;
    private Map<String, Object> payload;
    private LocalDateTime timestamp;

    public DistributedEvent(String eventType, String source) {
        this.eventId = UUID.randomUUID().toString();
        this.eventType = eventType;
        this.source = source;
        this.payload = new HashMap<>();
        this.timestamp = LocalDateTime.now();
    }

    public void addPayload(String key, Object value) {
        payload.put(key, value);
    }

    // Getters and Setters
}

/**
 * 分布式事件发布器
 */
@Service
@Slf4j
public class DistributedEventPublisher {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    private static final String EXCHANGE = "event.exchange";

    /**
     * 发布分布式事件
     */
    public void publish(DistributedEvent event) {
        String routingKey = "event." + event.getEventType();

        log.info("发布分布式事件: {} -> {}", event.getEventType(), routingKey);

        rabbitTemplate.convertAndSend(EXCHANGE, routingKey, event);
    }

    /**
     * 发布用户注册事件(分布式)
     */
    public void publishUserRegister(User user) {
        DistributedEvent event = new DistributedEvent("user.register", "user-service");
        event.addPayload("userId", user.getId());
        event.addPayload("username", user.getUsername());
        event.addPayload("email", user.getEmail());

        publish(event);
    }

    /**
     * 发布订单创建事件(分布式)
     */
    public void publishOrderCreated(Order order) {
        DistributedEvent event = new DistributedEvent("order.created", "order-service");
        event.addPayload("orderId", order.getId());
        event.addPayload("orderNo", order.getOrderNo());
        event.addPayload("amount", order.getAmount());

        publish(event);
    }
}

/**
 * 分布式事件监听器
 */
@Component
@Slf4j
public class DistributedEventListener {

    /**
     * 监听用户注册事件
     */
    @RabbitListener(queues = "user.register.queue")
    public void handleUserRegister(DistributedEvent event) {
        log.info("收到用户注册事件: {}", event.getEventId());

        Long userId = (Long) event.getPayload().get("userId");
        String email = (String) event.getPayload().get("email");

        // 处理用户注册后的业务
        sendWelcomeEmail(email);
    }

    /**
     * 监听订单创建事件
     */
    @RabbitListener(queues = "order.created.queue")
    public void handleOrderCreated(DistributedEvent event) {
        log.info("收到订单创建事件: {}", event.getEventId());

        String orderNo = (String) event.getPayload().get("orderNo");

        // 处理订单创建后的业务
        processOrderCreated(orderNo);
    }

    private void sendWelcomeEmail(String email) {
        log.info("发送欢迎邮件: {}", email);
    }

    private void processOrderCreated(String orderNo) {
        log.info("处理订单创建: {}", orderNo);
    }
}

五、Spring内置事件

5.1 容器生命周期事件

java 复制代码
/**
 * 监听Spring容器生命周期事件
 */
@Component
@Slf4j
public class ApplicationLifecycleListener {

    /**
     * 容器刷新事件
     */
    @EventListener
    public void handleContextRefreshed(ContextRefreshedEvent event) {
        log.info("容器刷新完成");
        ApplicationContext context = event.getApplicationContext();
        log.info("Bean数量: {}", context.getBeanDefinitionCount());
    }

    /**
     * 容器启动事件
     */
    @EventListener
    public void handleContextStarted(ContextStartedEvent event) {
        log.info("容器启动");
    }

    /**
     * 容器停止事件
     */
    @EventListener
    public void handleContextStopped(ContextStoppedEvent event) {
        log.info("容器停止");
        // 清理资源
    }

    /**
     * 容器关闭事件
     */
    @EventListener
    public void handleContextClosed(ContextClosedEvent event) {
        log.info("容器关闭");
        // 释放资源、保存状态等
    }
}

5.2 Web应用事件

java 复制代码
/**
 * 监听Web应用事件
 */
@Component
@Slf4j
public class WebApplicationListener {

    /**
     * ServletContext初始化事件
     */
    @EventListener
    public void handleServletContextInitialized(ServletRequestHandledEvent event) {
        log.info("Servlet请求处理: {} {}, 耗时: {}ms",
                event.getMethod(),
                event.getRequestUrl(),
                event.getProcessingTimeMillis());
    }
}

六、最佳实践

6.1 事件设计原则

java 复制代码
/**
 * 1. 事件应该是不可变的
 */
public class ImmutableEvent extends ApplicationEvent {

    private final String data;
    private final LocalDateTime timestamp;

    public ImmutableEvent(Object source, String data) {
        super(source);
        this.data = data;
        this.timestamp = LocalDateTime.now();
    }

    // 只提供getter,不提供setter
    public String getData() { return data; }
    public LocalDateTime getTimestamp() { return timestamp; }
}

/**
 * 2. 事件命名应该清晰表达意图
 */
// ✓ 好的命名
public class UserRegisteredEvent extends ApplicationEvent { }
public class OrderCancelledEvent extends ApplicationEvent { }
public class PaymentCompletedEvent extends ApplicationEvent { }

// ✗ 不好的命名
public class Event1 extends ApplicationEvent { }
public class UserEvent extends ApplicationEvent { }

/**
 * 3. 监听器应该独立、无状态
 */
@Component
public class GoodListener {

    @EventListener
    public void handle(UserRegisterEvent event) {
        // 处理逻辑独立,不依赖类成员变量
        sendEmail(event.getUser().getEmail());
    }

    private void sendEmail(String email) {
        // ...
    }
}

6.2 异常处理

java 复制代码
/**
 * 事件监听器异常处理
 */
@Component
@Slf4j
public class SafeEventListener {

    /**
     * 捕获异常,避免影响其他监听器
     */
    @EventListener
    public void handleWithExceptionHandling(UserRegisterEvent event) {
        try {
            // 可能抛出异常的代码
            sendEmail(event.getUser().getEmail());
        } catch (Exception e) {
            log.error("发送邮件失败", e);
            // 记录错误,但不抛出,避免影响其他监听器
        }
    }

    private void sendEmail(String email) throws Exception {
        // 可能抛出异常
    }
}

/**
 * 自定义异常处理器
 */
@Component
public class CustomErrorHandler implements ErrorHandler {

    private static final Logger log = LoggerFactory.getLogger(CustomErrorHandler.class);

    @Override
    public void handleError(Throwable t) {
        log.error("事件监听器执行异常", t);
        // 可以发送告警
    }
}

/**
 * 配置异步事件的异常处理器
 */
@Configuration
public class AsyncEventConfig {

    @Bean
    public SimpleApplicationEventMulticaster applicationEventMulticaster() {
        SimpleApplicationEventMulticaster multicaster =
            new SimpleApplicationEventMulticaster();

        // 设置异常处理器
        multicaster.setErrorHandler(new CustomErrorHandler());

        return multicaster;
    }
}

七、总结

核心知识点回顾

java 复制代码
Spring事件机制核心要点
│
├── 基础组件
│   ├── ApplicationEvent(事件)
│   ├── ApplicationListener(监听器)
│   ├── ApplicationEventPublisher(发布器)
│   └── ApplicationEventMulticaster(广播器)
│
├── 监听方式
│   ├── 实现ApplicationListener接口
│   └── 使用@EventListener注解
│
├── 高级特性
│   ├── 条件监听(SpEL表达式)
│   ├── 异步监听(@Async)
│   ├── 监听顺序(@Order)
│   ├── 泛型事件
│   └── 事务事件(@TransactionalEventListener)
│
├── 实战应用
│   ├── 用户注册通知
│   ├── 订单状态变更
│   ├── 系统监控告警
│   ├── 数据变更审计
│   └── 分布式事件
│
└── 最佳实践
    ├── 事件不可变
    ├── 监听器独立
    ├── 异常处理
    └── 异步执行耗时操作

Spring事件机制提供了一种优雅的方式来实现组件间的解耦通信。通过合理使用事件机制,可以让代码更加灵活、可维护,易于扩展。在实际项目中,事件机制广泛应用于用户行为追踪、系统监控、业务流程解耦等场景。


相关推荐
鱼锦0.02 小时前
基于spring+vue把图片文件上传至阿里云oss容器并回显
java·vue.js·spring
好好研究3 小时前
SpringMVC框架 - 获取请求参数常用的注解
java·spring·mvc
雨中飘荡的记忆3 小时前
Spring表达式详解
spring
n***63274 小时前
SpringCloud 微服务框架
spring·spring cloud·微服务
切糕师学AI4 小时前
Spring 中的 @Service 注解
java·spring
想不明白的过度思考者4 小时前
Spring Web MVC从入门到实战
java·前端·spring·mvc
p***95005 小时前
spring Profile
java·数据库·spring
艺杯羹5 小时前
从Spring到SpringBoot3的演进:缺陷、优化与最新实践要求
java·spring boot·spring
极光代码工作室6 小时前
基于SpringBoot的校园招聘信息管理系统的设计与实现
java·前端·spring