Spring Boot事件的全面指南:事件类、发布者、监听器、异步、条件

发布时间 2023-04-10 09:36:36作者: 菜菜聊架构

ApplicationEvent介绍

SpringBoot中的ApplicationEvent是一种基于观察者模式实现的事件处理方式,它可以用于在Spring容器内部发布和订阅消息。事件监听与发布的过程如下:

  • 事件类(Event):继承自ApplicationEvent类,用于封装事件数据。从Spring Framework 4.2开始,事件类不需要继承ApplicationEvent类,可以是任意对象。
  • 发布者(Publisher):注入ApplicationEventPublisher对象,使用publishEvent()方法发布事件。
  • 监听器(Listener):实现ApplicationListener接口,重写onApplicationEvent()方法处理事件。监听器可以使用@Component注解注册为一个Bean,也可以使用@EventListener注解标注一个方法作为监听器。

事件监听与发布的运用场景有很多,比如:

  • 在Spring Boot启动时初始化数据或资源,比如加载配置文件、做安全认证等。
  • 在Spring Boot应用中实现异步处理,比如发送邮件、执行定时任务等。
  • 在Spring Boot应用中实现业务逻辑的解耦,比如订单支付成功后通知库存服务、物流服务等。

示例

在更新user对象后,发布一个事件,让一个监听器将user对象保存到redis中。为了实现这个功能,参考以下步骤:

  • 创建一个UserUpdateEvent类,不需要继承自ApplicationEvent类,只需要封装user对象。
  • 创建一个UserUpdatePublisher类,注入ApplicationEventPublisher对象,用于发布UserUpdateEvent。
  • 创建一个UserUpdateListener类,不需要实现ApplicationListener接口,只需要使用@EventListener和@Async注解标注一个方法作为异步监听器。
  • 在需要更新user对象的地方,调用UserUpdatePublisher的publishEvent()方法。

示例代码如下:

// UserUpdateEvent.java
public class UserUpdateEvent {
  
  private User user;
  public UserUpdateEvent(User user) {
    this.user = user;
  }
  public User getUser() {
    return user;
  }
}

// UserUpdatePublisher.java
@Component
public class UserUpdatePublisher {
  
  @Autowired
  private ApplicationEventPublisher applicationEventPublisher;
  
  public void publishEvent(User user) {
    System.out.println("Publishing user update event.");
    UserUpdateEvent userUpdateEvent = new UserUpdateEvent(user);
    applicationEventPublisher.publishEvent(userUpdateEvent);
  }
}

// UserUpdateListener.java
@Component
public class UserUpdateListener {
  
  @Autowired
  private RedisTemplate<String, Object> redisTemplate;

  @EventListener
  @Async
  public void onUserUpdate(UserUpdateEvent event) {
    System.out.println("Listening to user update event.");
    User user = event.getUser();
    // save user object to redis
    redisTemplate.opsForValue().set(user.getId(), user);
  }
}

// SomeService.java
@Service
public class SomeService {
  
  @Autowired
  private UserRepository userRepository;
  
  @Autowired
  private UserUpdatePublisher userUpdatePublisher;
  
  public void updateUser(User user) {
    // update user object in database
    userRepository.save(user);
    
    // publish user update event
    userUpdatePublisher.publishEvent(user);
  }
}

注意:使用@Async注解实现异步事件监听时,需要在Spring Boot应用中开启异步支持,即在启动类或配置类上添加@EnableAsync注解。

@EventListener注解SpEL表达式实现条件事件监听

使用SpEL表达式实现条件事件监听的方法是,在@EventListener注解中添加condition属性,指定一个布尔值的SpEL表达式,表示事件监听的条件。例如:

@EventListener(condition = "#event.user.name == '张三'")
public void onUserUpdate(UserUpdateEvent event) {
  // 只有当user对象的name属性为张三时,才会执行这个方法
}

SpEL表达式中可以使用event变量来引用事件对象,也可以使用root变量来引用事件对象或方法参数。例如:

@EventListener(condition = "#root.event.user.age > 18")
public void onUserUpdate(UserUpdateEvent event) {
  // 只有当user对象的age属性大于18时,才会执行这个方法
}

@EventListener(condition = "#root.args[0].user.gender == '男'")
public void onUserUpdate(UserUpdateEvent event) {
  // 只有当user对象的gender属性为男时,才会执行这个方法
}

SpEL表达式中还可以使用Spring容器中的Bean或属性。例如:

@EventListener(condition = "@userService.isAdmin(#event.user)")
public void onUserUpdate(UserUpdateEvent event) {
  // 只有当userService Bean的isAdmin方法返回true时,才会执行这个方法
}

@EventListener(condition = "#event.user.score >= ${user.minScore}")
public void onUserUpdate(UserUpdateEvent event) {
  // 只有当user对象的score属性大于等于配置文件中的user.minScore属性时,才会执行这个方法
}

总结

以上主要涉及了几个方面:

  • Spring Boot中的ApplicationEvent是一种基于观察者模式实现的事件处理方式,它可以用于在Spring容器内部发布和订阅消息,实现业务逻辑的解耦和异步处理。
  • 事件监听与发布的过程涉及到三个角色:事件类、发布者和监听器。事件类用于封装事件数据,发布者用于发布事件,监听器用于处理事件。
  • 事件类可以继承自ApplicationEvent类,也可以是任意对象。从Spring Framework 4.2开始,Spring支持使用任意对象作为事件类,不再强制要求事件类必须继承自ApplicationEvent类。
  • 监听器可以实现ApplicationListener接口,也可以使用@EventListener注解标注一个方法。使用@EventListener注解可以简化监听器的编写,不需要实现接口或注册Bean。
  • 监听器可以使用@Async注解实现异步事件监听,这样可以提高性能和响应速度。使用@Async注解实现异步事件监听时,需要在Spring Boot应用中开启异步支持,即在启动类或配置类上添加@EnableAsync注解。
  • 监听器可以使用@EventListener注解中的condition属性指定一个SpEL表达式,表示事件监听的条件。SpEL表达式中可以使用event变量或root变量引用事件对象或方法参数,也可以使用Spring容器中的Bean或属性。