SpringBoot - 事件机制使用详解(ApplicationEvent、ApplicationListener)

SpringBoot - 事件机制使用详解(ApplicationEvent、ApplicationListener)

Spring 事件机制使用观察者模式来传递事件和消息。我们可以使用 ApplicationEvent 类来发布事件,然后使用 ApplicationListener 接口来监听事件。当事件发生时,所有注册的 ApplicationListener 都会得到通知。事件用于在松散耦合的组件之间交换信息。由于发布者和订阅者之间没有直接耦合,因此可以在不影响发布者的情况下修改订阅者,反之亦然。下面通过样例样式事件机制的使用。

1,基本用法

(1)首先我们创建一个自定义事件类 MyEvent,该类继承自 ApplicationEvent 类。

// 自定义事件类
public class MyEvent extends ApplicationEvent {
 
  private String message;
 
  public MyEvent(Object source, String message) {
    super(source);
    this.message = message;
  }
 
  public String getMessage() {
    return message;
  }
}

(2)接着定义一个事件监听器类 MyEventListener,该类实现 ApplicationListener 接口,并注册为 Spring 的组件。只要监听器对象在 Spring 应用程序上下文中注册,它就会接收事件。当 Spring 路由一个事件时,它使用监听器的签名来确定它是否与事件匹配。

// 事件监听器
@Component
public class MyEventListener implements ApplicationListener<MyEvent> {
  // 事件发生时执行
  @Override
  public void onApplicationEvent(MyEvent event) {
    System.out.println("接收到事件: " + event.getMessage());
    // 模拟事件处理
    try {
      Thread.sleep(3000);
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
  }
}

(3)最后我们可以使用 ApplicationContext 的 publishEvent 方法来发布事件。

@RestController
public class HelloController {
  @Autowired
  private ApplicationContext context;
 
  @GetMapping("/hello")
  public void hello() {
    System.out.println("准备发送事件");
    context.publishEvent(new MyEvent(this, "welcome to hangge.com"));
    System.out.println("事件发送完毕");
  }
}

(4)启动项目测试一下,我们访问 /hello 接口时,控制台输出如下,说明事件机制运行成功。

  • 注意:spring 事件是同步的,这意味着发布者线程将阻塞,直到所有监听都完成对事件的处理为止。

在这里插入图片描述

2,使用 @EventListener 监听事件

(1)上面样例我们通过实现 ApplicationListener 接口来定义监听器。从 Spring 4.1 开始,可以使用 @EventListener 注解的方法,以自动注册与该方法签名匹配的 ApplicationListener(监听器类同样需要注册为 Spring 的组件)。下面代码的效果同上面是一样的:

// 事件监听器
@Component
public class MyEventListener{
  // 使用注解实现事件监听
  @EventListener
  public void onApplicationEvent(MyEvent event) {
    System.out.println("接收到事件: " + event.getMessage());
    // 模拟事件处理
    try {
      Thread.sleep(3000);
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
  }
}

(2)我们可以使用 @EventListener 注解的 value 属性来指定我们要监听的事件类型。比如下面代码来监听 MyEvent 类型的事件:
如果需要同时指定多个事件类型可以这么写:@EventListener({MyEvent.class,AnotherEvent.class})。

// 事件监听器
@Component
public class MyEventListener{
  // 使用注解实现事件监听
  @EventListener(MyEvent.class)
  public void onApplicationEvent(MyEvent event) {
    System.out.println("接收到事件: " + event.getMessage());
  }
}

(3)我们可以使用 @EventListener 注解的 condition 属性来指定事件监听器的执行条件。在下面的代码中,#event.message == ‘hello’ 是一个 SpEL 表达式,表示当事件的 message 属性值为 hello 时,事件监听器才会被执行。
(1)SpEL (Spring Expression Language) 是一种强大的表达式语言,用于在运行时执行各种表达式。我们可以使用 SpEL 表达式来访问对象的属性、调用对象的方法、执行运算等。
(2)SpEL 表达式语法如下:
属性访问:使用 . 操作符访问对象的属性,例如,object.property 表示访问对象 object 的属性 property。
方法调用:使用 () 操作符调用对象的方法,例如,object.method() 表示调用对象 object 的方法 method。
运算符:SpEL 支持常用的运算符,包括算术运算符、关系运算符、逻辑运算符等。
(3)SpEL 表达式还支持一些特殊的操作符和函数,如下所示:
? 操作符:三目运算符,形如 (condition ? then : else),表示当 condition 为真时返回 then,否则返回 else。
instanceof 操作符:用于判断对象是否为某个类型,形如 object instanceof T,表示对象 object 是否为类型 T。
t() 函数:将对象转换为给定的类型,形如 t(T),表示将对象转换为类型 T。
elvis 操作符:用于判断对象是否为空,形如 object ?: defaultValue,表示如果对象不为空则返回对象,否则返回默认值。

// 事件监听器
@Component
public class MyEventListener{
  // 使用注解实现事件监听
  @EventListener(condition = "#event.message == 'hello'")
  public void onApplicationEvent(MyEvent event) {
    System.out.println("接收到事件: " + event.getMessage());
  }
}

(4)对于使用 @EventListener 注解并定义为具有返回类型的方法,Spring 会将结果作为新事件发布。在下面的示例中,第一个方法返回的 AnotherEvent 将被发布,然后由第二个方法处理。

// 事件监听器
@Component
public class MyEventListener{
  @EventListener
  public AnotherEvent listener1(MyEvent event) {
    // 处理事件
    System.out.println("事件监听器 1 接收到事件: " + event.getMessage());
    return new AnotherEvent(this, "转发" + event.getMessage());
  }
 
  @EventListener
  public void listener2(AnotherEvent event) {
    // 处理事件
    System.out.println("事件监听器 2 接收到事件: " + event.getMessage());
  }
}

3,使用 @Order 指定优先级

(1)当 Spring 发布一个事件时,会调用所有能处理这个事件的事件监听器方法。如果你有多个事件监听器方法,那么 Spring 会依次调用这些方法。比如下面样例,当发布一个 MyEvent 事件时,Spring 会依次调用这两个方法。

// 事件监听器
@Component
public class MyEventListener{
  @EventListener
  public void listener1(MyEvent event) {
    // 处理事件
    System.out.println("事件监听器 1 接收到事件: " + event.getMessage());
  }
 
  @EventListener
  public void listener2(MyEvent event) {
    // 处理事件
    System.out.println("事件监听器 2 接收到事件: " + event.getMessage());
  }
}

在这里插入图片描述

(2)我们可以使用 @Order 注解来指定事件监听器方法的优先级。@Order 注解可以标注在类上或方法上,表示这个类或方法的优先级。数值越小,优先级越高。

// 事件监听器
@Component
public class MyEventListener{
  @Order(2)
  @EventListener
  public void listener1(MyEvent event) {
    // 处理事件
    System.out.println("事件监听器 1 接收到事件: " + event.getMessage());
  }
 
  @Order(1)
  @EventListener
  public void listener2(MyEvent event) {
    // 处理事件
    System.out.println("事件监听器 2 接收到事件: " + event.getMessage());
  }
}

在这里插入图片描述

4,使用 @Async 实现异步事件监听

(1)从第一个样例运行结果可以看出默认 spring 事件是同步的,这意味着发布者线程将阻塞,直到所有侦听器都完成对事件的处理为止。我们可以使用 @Async 注解来标注一个事件监听器方法,表示这个方法是一个异步方法,应该在独立的线程中执行。

// 事件监听器
@Component
public class MyEventListener{
  // 使用注解实现事件监听
  @Async
  @EventListener
  public void onApplicationEvent(MyEvent event) {
    System.out.println("接收到事件: " + event.getMessage());
    // 模拟事件处理
    try {
      Thread.sleep(3000);
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
  }
}

(2)同时我们还需要在配置类(@Configuration 类之一或 @SpringBootApplication 类)中启用异步处理,才能使用 @Async 注解。

@Configuration
@EnableAsync
public class MyConfig {
    // 配置类
}

(3)最后测试一下,可看到实现了异步事件监听:
在这里插入图片描述

附:Spring Boot 内置的 Application Event

(1)Spring Boot 中包含了一些与 SpringApplication 生命周期相关的内置 Application Event,包括:

  • ApplicationStartingEvent:在 Spring Boot 应用程序启动之前发布。
  • ApplicationEnvironmentPreparedEvent:在 Spring Boot 应用程序的环境已经准备好,但正在创建 Application Context 上下文之前发布。
  • ApplicationContextInitializedEvent:当 Spring Boot 应用程序 Application Context 上下文准备就绪并且调用
  • ApplicationContextInitializers,但尚未加载 bean 定义时发布。
  • ApplicationPreparedEvent:在 Spring Boot 应用程序的 Application Context 上下文已经创建,但尚未刷新之前发布。
  • ApplicationStartedEvent:在 Spring Boot 应用程序的 Application Context 上下文已经刷新,但尚未启动之前发布。
  • ApplicationReadyEvent:在 Spring Boot 应用程序已经启动并准备接受请求之后发布。
  • ApplicationFailedEvent:在 Spring Boot 应用程序启动失败时发布。

(2)假设我们需要监听 ApplicationStartingEvent,则首先定义一个监听器类:

// 事件监听器
public class MyEventListener implements ApplicationListener<ApplicationStartingEvent> {
  // 事件发生时执行
  @Override
  public void onApplicationEvent(ApplicationStartingEvent event) {
    // 处理事件
    System.out.println("应用程序将要启动");
  }
}

(3)由于该事件实际上是在 Application Context 创建前触发的,这时的 Bean 是不能被加载的。所以我们不能在这个监听器类上中使用 @Component 注册监听器,只能通过 SpringApplication 注册监听器。我们对项目启动类做如下修改:
注意:对于ApplicationStartedEvent、ApplicationReadyEvent、ApplicationFailedEvent 这些在 Application Context上下文已经创建完毕之后,所以可以直接使用 @Component 注册,不需要下面这个步骤。

@SpringBootApplication
public class RmiserverApplication {
 
  public static void main(String[] args) {
    SpringApplication app = new SpringApplication(RmiserverApplication.class);
    app.addListeners(new MyEventListener()); //注册监听器
    app.run(args);
  }
}

或者也可以使用使用 SpringApplicationBuilder 注册监听器:

@SpringBootApplication
public class RmiserverApplication {
 
  public static void main(String[] args) {
    new SpringApplicationBuilder().sources(RmiserverApplication.class)
            .listeners(new MyEventListener()) //注册监听器
            .run(args);
  }
}

(4)启动项目,可以看到控制台输出如下:
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring 框架中,ApplicationEvent 是一个事件抽象类,用于表示应用程序中发生的事件。它的子类可以表示各种类型的事件,比如用户注册、订单支付、系统启动等等。当一个事件发生时,应用程序可以创建一个对应的 ApplicationEvent 子类对象,并将其传递给 Spring事件发布者,以便其他监听器能够处理该事件。 下面是一个示例,演示了如何定义一个 ApplicationEvent 子类: ``` import org.springframework.context.ApplicationEvent; public class OrderEvent extends ApplicationEvent { private static final long serialVersionUID = 1L; private Order order; public OrderEvent(Object source, Order order) { super(source); this.order = order; } public Order getOrder() { return order; } } ``` 在这个示例中,我们创建了一个 OrderEvent 类,它继承了 ApplicationEvent 类。我们还定义了一个 Order 对象作为事件的附加数据,并提供了相应的构造方法和访问方法。 当我们需要触发一个 OrderEvent 事件时,可以在应用程序中创建一个 OrderEvent 对象,并将其传递给 Spring事件发布者,如下所示: ``` import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; public class OrderService implements ApplicationEventPublisherAware { private ApplicationEventPublisher eventPublisher; public void placeOrder(Order order) { // 业务逻辑处理 // 发布订单事件 OrderEvent event = new OrderEvent(this, order); eventPublisher.publishEvent(event); } @Override public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) { this.eventPublisher = eventPublisher; } } ``` 在这个示例中,我们在 OrderService 类中通过实现 ApplicationEventPublisherAware 接口,来获取 Spring事件发布者对象。当需要发布一个 OrderEvent 事件时,我们创建一个 OrderEvent 对象,并将其传递给事件发布者,从而触发事件。其他监听器可以通过实现 ApplicationListener 接口来处理这个事件

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值