【附录】Spring 事件机制 基础及应用

138 阅读3分钟

此文是 【Spring 容器详解】-> 【 ApplicationContext 做了哪些企业化的增强?】的支节点。

Spring的事件机制是基于观察者模式实现的,它提供了一种松耦合的方式来处理应用程序中的事件。主要包含以下几个核心组件:

核心组件

  • ApplicationEvent: 所有事件的基类
  • ApplicationListener: 事件监听器接口
  • ApplicationEventPublisher: 事件发布接口
  • ApplicationEventMulticaster: 事件多播器,负责管理监听器和分发事件

基本使用方法

1. 定义事件

事件必须继承自ApplicationEvent类:

public class UserRegisteredEvent extends ApplicationEvent {
    private final User user;

    public UserRegisteredEvent(Object source, User user) {
        super(source);  // source通常是发布事件的组件
        this.user = user;
    }

    public User getUser() {
        return user;
    }
}

注意:为什么事件类必须要有带参数的构造器?,source参数又是什么?

  1. 因为ApplicationEvent没有无参构造器,只有带source参数的构造器
  2. 子类必须显式调用父类的带参构造器:super(source)
  3. source参数表示发布事件的组件对象 ->【什么是组件对象?】(事件最初发生的对象或与事件关联的对象)
  4. 根据source可以在日志中可以看到事件来源,监听器可能需要根据事件源做不同处理

2. 创建事件监听器

有两种方式创建监听器:

方式一:实现ApplicationListener接口

@Component
public class UserRegisteredEventListener implements ApplicationListener<UserRegisteredEvent> {
    @Override
    public void onApplicationEvent(UserRegisteredEvent event) {
        User user = event.getUser();
        System.out.println("用户 " + user.getUsername() + " 注册成功,发送欢迎邮件...");
    }
}

方式二:使用@EventListener注解(推荐)

@Component
public class UserEventListener {
    
    @EventListener
    public void handleUserRegistered(UserRegisteredEvent event) {
        User user = event.getUser();
        System.out.println("用户 " + user.getUsername() + " 注册成功,发送欢迎邮件...");
    }
    
    @EventListener
    public void handleUserLogin(UserLoginEvent event) {
        // 处理用户登录事件
    }
}

3. 发布事件

通过ApplicationContext发布事件:

@Service
public class UserService {
    @Autowired
    private ApplicationContext applicationContext;

    public void registerUser(User user) {
        // 执行用户注册逻辑
        UserRegisteredEvent event = new UserRegisteredEvent(this, user);
        applicationContext.publishEvent(event);
    }
}

高级特性

1. 异步事件处理

默认情况下,Spring事件是同步处理的。要实现异步处理,需要配置TaskExecutor

@Configuration
public class EventConfig {
    
    @Bean
    public TaskExecutor taskExecutor() {
        return new SimpleAsyncTaskExecutor();
    }
    
    @Bean("applicationEventMulticaster")
    public SimpleApplicationEventMulticaster applicationEventMulticaster(TaskExecutor taskExecutor) {
        SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
        multicaster.setTaskExecutor(taskExecutor);
        return multicaster;
    }
}

2. 条件化事件监听

使用@EventListener的条件表达式:

@Component
public class ConditionalEventListener {
    
    @EventListener(condition = "#event.user.username == 'admin'")
    public void handleAdminUserRegistered(UserRegisteredEvent event) {
        System.out.println("管理员用户注册,执行特殊处理...");
    }
}

3. 事件监听器排序

使用@Order注解控制监听器执行顺序:

@Component
@Order(1)
public class FirstEventListener {
    @EventListener
    public void handleEvent(MyEvent event) {
        System.out.println("第一个监听器执行");
    }
}

@Component
@Order(2)
public class SecondEventListener {
    @EventListener
    public void handleEvent(MyEvent event) {
        System.out.println("第二个监听器执行");
    }
}

事件机制核心原理

注意:核心源码部分,另开一个章节介绍【附录】Spring 事件机制源码部分剖析-待补充

核心流程

  1. 事件发布: 调用ApplicationContext.publishEvent()
  2. 事件获取: ApplicationEventMulticaster获取所有匹配的监听器
  3. 事件分发: 将事件分发给所有监听器
  4. 事件处理: 监听器执行相应的处理逻辑

关键类分析

ApplicationEventMulticaster:

  • 管理所有的事件监听器
  • 负责事件的广播和分发
  • 支持同步和异步事件处理

SimpleApplicationEventMulticaster:

  • ApplicationEventMulticaster的默认实现
  • 通过TaskExecutor支持异步处理

监听器注册机制

Spring在启动时会:

  1. 扫描所有实现了ApplicationListener的Bean
  2. 扫描所有带有@EventListener注解的方法
  3. 将这些监听器注册到ApplicationEventMulticaster

实际应用场景

1. 业务解耦

// 用户注册后需要执行多个操作:发送邮件、记录日志、更新缓存等
@Service
public class UserService {
    public void registerUser(User user) {
        // 核心业务逻辑
        saveUser(user);
        
        // 发布事件,其他组件异步处理
        applicationContext.publishEvent(new UserRegisteredEvent(this, user));
    }
}

2. 系统监控

@Component
public class SystemMonitorListener {
    
    @EventListener
    public void handleUserAction(UserActionEvent event) {
        // 记录用户行为日志
        logUserAction(event);
        
        // 更新用户活跃度统计
        updateUserActivityStats(event);
    }
}

总结

Spring的事件机制提供了一种优雅的方式来处理应用程序中的各种事件,能够有效降低组件间的耦合度,提高代码的可维护性和可扩展性。通过合理使用事件机制,可以实现业务逻辑的解耦,提高系统的响应性和可维护性。