Spring Event事件处理

Spring 事件处理基于 Java 观察者模式扩展。Spring 应用上下文中发布了各种事件,此外 Spring 还允许我们发送和处理自定义的事件,本篇将对 Spring 的事件机制使用进行详细介绍。


基础使用

1. 定义事件

定义事件:需要继承ApplicationEvent,例如:

public class UserRegisteredEvent extends ApplicationEvent {
    public UserRegisteredEvent(User user) {
        super(user); // 调用父类构造器,传入事件源
    }

    public User getUser() {
        return (User) getSource();
    }
}

2. 定义事件发布器

定义事件发布器:使用ApplicationEventPublisherAware获取ApplicationEventPublisher,例如:

@Component
public class UserEventPublisher implements ApplicationEventPublisherAware {

    private ApplicationEventPublisher applicationEventPublisher;

    public void publishUserRegistered(User user) {
        applicationEventPublisher.publishEvent(new UserRegisteredEvent(user));
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}

3. 定义事件监听器

定义事件监听器可以通过两种方式:

  1. 实现ApplicationListener接口,监听特定事件,例如:
@Component
public class UserEventListener implements ApplicationListener<UserRegisteredEvent> {

    @Override
    public void onApplicationEvent(UserRegisteredEvent event) {
        User user = event.getUser();
        // 对user对象进行相关处理...
    }
}
  1. 使用@EventListener注解直接标注在方法上,该方法会自动注册为事件监听器,无需实现ApplicationListener接口。
@Component
public class UserEventListener {

    @EventListener
    public void onUserRegistered(UserRegisteredEvent event) {
        // 处理逻辑
    }
}

4.发布与订阅事件

注入时间发布器进行时间发布

@Autowired
private UserEventPublisher userEventPublisher;

@Autowired
private UserService userService;

public void registerUser(User user) {
    userService.register(user);
    userEventPublisher.publishUserRegistered(user);
}

高级使用

异步事件

使用@Async注解实现异步事件

  1. 在项目主类上加入@EnableAsync注解
  2. 改造监听器,在原来的方法上加入@Async注解
@Component
public class UserEventListener {

  	@Async
    @EventListener
    public void onUserRegistered(UserRegisteredEvent event) {
        // 处理逻辑
    }
}

事件过滤

如果我们想对事件进行限制,某一部分满足条件的事件才发送邮件,可以使用condition属性来指定限制的条件。

@Component
public class UserEventListener {

   	@EventListener(condition = "#event.userId > 5")
    public void onUserRegistered(UserRegisteredEvent event) {
        // 处理逻辑
    }
}

顺序监听

每个事件都可以定义多个监听器,默认情况下监听器执行的顺序是未知的。可以使用 @Order 注解来指定监听器的权重,来确定监听器的执行顺序。

@Component
public class UserEventListener {

  	@Order(1)
   	@EventListener
    public void onUserRegistered(UserRegisteredEvent event) {
        // 处理逻辑
    }
  
  	@Order(2)
   	@EventListener
    public void onUserRegistered(UserRegisteredEvent event) {
        // 处理逻辑
    }
  
  	@Order(3)
   	@EventListener
    public void onUserRegistered(UserRegisteredEvent event) {
        // 处理逻辑
    }
}

事务处理

在Spring中,可以使用@TransactionalEventListener注解对监听器进行标注,使用此注解,被标注的方法将被纳入到事务管理的范围。此注解是@EventListener的扩展,它允许你将事件的监听绑定到某个事务阶段。可以通过phase属性对事务阶段进行设置。下面是phase可设置的所有事务阶段:

  • 1、AFTER_COMMIT(默认值),用于在事务成功完成后触发事件
  • 2、AFTER_ROLLBACK,用于事务回滚是触发事件
  • 3、AFTER_COMPLETION,用于事务完成后触发事件(AFTER_COMMIT和AFTER_ROLLBACK的一种模糊表述)
  • 4、BEFORE_COMMIT,用于事务提交前触发事件
@Component
public class UserEventListener {

   	@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void onUserRegistered(UserRegisteredEvent event) {
        // 处理逻辑
    }
}

自定义@Async异步线程池

在 Spring 中,通过 @Async 注解可以实现异步方法调用,但默认情况下它使用的是一个简单的线程池。如果你想自定义线程池来管理异步任务,可以按照以下步骤操作:

  1. 创建自定义线程池: 首先,你需要创建一个自定义的线程池,可以使用 Java 提供的 ExecutorService 接口的实现类,如 ThreadPoolExecutor
  2. 配置线程池: 在 Spring 配置中,你可以使用 @Bean 注解将你的自定义线程池注入到 Spring 容器中。你可以在配置类中创建这个 Bean。
  3. 使用自定义线程池: 在异步方法上添加 @Async 注解时,通过 value 属性指定要使用的线程池的 Bean 名称,以让 Spring 使用你自定义的线程池。
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    @Bean(name = "customExecutor")
    public Executor customExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(30);
        executor.setThreadNamePrefix("CustomExecutor-");
        executor.initialize();
        return executor;
    }
}

然后,在需要异步执行的方法上使用 @Async 注解,并指定使用的线程池的 Bean 名称:

@Component
public class UserEventListener {

    @Async("customExecutor")
    @EventListener
    public void onUserRegistered(UserRegisteredEvent event) {
        // 处理逻辑
    }
}

Spring系统事件

在Spring中,有一些系统事件,都是基于ApplicationEvent扩展的,可以自己看实现ApplicationEvent的实现类来查看系统默认事件。下图中ApplicationContextEvent是Spring上下问的一些事件;SpringApplicationEvent是Spring Boot中的一些事件。

如果需要我们可以监听Spring系统事件来实现一些功能。正常只有框架需要,业务开发不需要。

Spring Event事件处理_Async

自定义ApplicationEventMulticaster

ApplicationEventMulticaster是spring中事件广播器接口,负责事件的广播发布。AbstractApplicationContext中使用initApplicationEventMulticaster()初始化事件广播器。自定义 ApplicationEventMulticaster 可以实现以下功能:

  1. 自定义事件派发策略: 通过自定义 ApplicationEventMulticaster,你可以实现自己的事件派发策略。默认情况下,Spring 使用 SimpleApplicationEventMulticaster,但你可以根据需要创建一个自定义的派发策略,例如,你可以实现异步事件派发,或者基于条件的事件派发策略。
  2. 集成消息中间件: 如果你想将 Spring 事件和消息中间件(如 RabbitMQ、Kafka 等)集成,可以自定义 ApplicationEventMulticaster 来实现这个集成。这样,你就可以在事件发布时将事件转换为消息,并通过消息中间件进行分发。
  3. 事件过滤和处理顺序控制: 通过自定义 ApplicationEventMulticaster,你可以添加事件过滤器,只有符合特定条件的事件才会被派发。你还可以控制事件监听器的处理顺序,确保监听器按照你定义的顺序依次处理事件。
  4. 多线程事件派发: 默认情况下,Spring 事件是同步派发的。但你可以通过自定义 ApplicationEventMulticaster 来实现异步事件派发,从而在事件发布时启动新的线程来处理事件。
  5. 与其他框架集成: 自定义 ApplicationEventMulticaster 还可以用于将 Spring 事件与其他框架的事件机制集成,从而实现不同框架之间的事件通信。

需要注意的是,自定义 ApplicationEventMulticaster 是一个高级用法,一般情况下使用 Spring 提供的默认实现已经足够满足需求。但在某些特定情况下,自定义 ApplicationEventMulticaster 可以提供更多的灵活性和定制性,以满足复杂的应用场景。

例如,自定义ApplicationEventMulticaster实现异步事件派发:

@Configuration
public class AsyncSpringEventConfig {
 	@Bean(name = "applicationEventMulticaster")
 	public ApplicationEventMulticaster applicationEventMulticaster(){
 		SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
 		multicaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
 		return multicaster;
 	}
}