轩辕李的博客 轩辕李的博客
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

轩辕李

勇猛精进,星辰大海
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Java

  • Spring

    • 基础

    • 框架

      • Spring容器初始化过程和Bean生命周期探究
      • Spring容器:从依赖管理到注解配置全解析
      • Spring事件探秘
        • 一、Spring事件的概述
          • 1. 什么是Spring事件
          • 2. 为什么使用Spring事件
        • 二、Spring事件的基本使用
          • 1. 创建事件
          • 2. 发布事件
          • 3. 监听事件
        • 三、Spring事件的高级特性
          • 1. 事件的顺序
          • 2. 事件的异步处理
          • 3. 事件的过滤
          • 4. 事件的继承
          • 5. 泛型支持
        • 四、Spring现有事件
          • 1. ApplicationContext事件
          • 2. Spring Boot事件
          • 3. Web应用事件
        • 五、事务绑定事件
          • 1. @TransactionalEventListener注解
          • 2. 注意事项
        • 六、总结
      • Spring AOP的应用
      • Spring 事务管理
      • Spring中的资源访问:Resource接口
      • Spring中的验证、数据绑定和类型转换
      • Spring表达式语言(SpELl)
      • Spring中的属性占位符
      • Spring数据缓冲区与编解码器详解
      • Spring对于原生镜像和AOT的支持
      • Spring中的数据访问:JDBC、R2DBC、ORM、Object-XML
      • Spring中的Web访问:Servlet API支持
      • Spring中的Web访问:WebSocket支持
      • Spring中的Web访问:响应式栈 WebFlux
      • Spring中的集成测试与单元测试
      • Spring与多种技术的集成
      • Spring框架版本新特性
    • Spring Boot

    • 集成

  • 其他语言

  • 工具

  • 后端
  • Spring
  • 框架
轩辕李
2023-08-06
目录

Spring事件探秘

# 一、Spring事件的概述

# 1. 什么是Spring事件

在Spring框架中,事件是一种用于消息传递和处理的机制。它允许应用程序中的不同组件之间进行解耦,通过触发事件和监听事件的方式进行通信。当某个事件发生时,所有监听该事件的组件都可以收到通知并执行相应的逻辑。

Spring事件 (opens new window)机制基于观察者模式,通过定义事件、发布事件和监听事件的接口,实现了事件的发布和订阅。事件的发布者不需要知道谁会监听它,而监听者也不需要直接与发布者进行耦合,从而提高了代码的灵活性和可维护性。

# 2. 为什么使用Spring事件

使用Spring事件机制有以下几个优势:

  • 解耦性:通过事件机制,各个组件之间的通信不再直接依赖于具体的实现类,而是通过事件进行解耦,降低了组件之间的耦合度。
  • 灵活性:通过发布和监听事件的方式,可以在不修改已有代码的情况下添加新的功能,实现代码的动态扩展。
  • 可扩展性:可以轻松地添加新的监听器来处理事件,从而实现更多的业务逻辑。
  • 可测试性:事件的发布和监听可以通过单元测试来验证,确保代码的正确性和稳定性。

# 二、Spring事件的基本使用

# 1. 创建事件

在Spring中,创建事件需要定义一个继承自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. 发布事件

发布事件是指在适当的时机将事件发送给所有监听器。在Spring中,可以通过ApplicationEventPublisher接口的publishEvent()方法来发布事件。

@Component
public class MyEventPublisher {

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    public void publishEvent(String message) {
        MyEvent event = new MyEvent(this, message);
        eventPublisher.publishEvent(event);
    }
}

# 3. 监听事件

监听事件是指在事件发生时执行相应的逻辑。在Spring中,可以通过实现ApplicationListener接口,并指定要监听的事件类型来监听事件。

@Component
public class MyEventListener implements ApplicationListener<MyEvent> {

    @Override
    public void onApplicationEvent(MyEvent event) {
        String message = event.getMessage();
        // 处理事件逻辑...
    }
}

通过以上步骤,我们可以实现事件的创建、发布和监听。当调用MyEventPublisher的publishEvent()方法时,所有监听MyEvent事件的监听器都会收到通知并执行相应的逻辑。这样,不同组件之间就可以通过事件进行解耦,并实现灵活的通信机制。

你也可以使用@EventListener注解来监听事件,这样就不需要实现ApplicationListener接口了。

@Component
public class MyEventListener {

    @EventListener
    public void onApplicationEvent(MyEvent event) {
        String message = event.getMessage();
        // 处理事件逻辑...
    }
}

# 三、Spring事件的高级特性

# 1. 事件的顺序

在Spring事件机制中,可以通过实现Ordered接口或使用@Order注解来指定事件的处理顺序。较小的值表示较高的优先级,同一优先级的事件按照它们被发布的顺序进行处理。

@Component
@Order(1)
public class MyEventListener1 implements ApplicationListener<MyEvent> {
    //...
}

@Component
@Order(2)
public class MyEventListener2 implements ApplicationListener<MyEvent> {
    //...
}

# 2. 事件的异步处理

Spring事件机制还支持将事件的处理异步化,即事件的发布和监听可以在不同的线程中进行。可以通过在方法上添加@Async注解来实现异步处理。

@Component
public class MyEventListener {

    @Async
    @EventListener
    public void handleMyEvent(MyEvent event) {
        // 异步处理事件逻辑...
    }
}

# 3. 事件的过滤

有时候只对特定条件下的事件感兴趣,可以通过在事件监听器的方法上添加条件注解来实现事件的过滤。

@Component
public class MyEventListener {

    @EventListener(condition = "#event.message.startsWith('Important')")
    public void handleMyEvent(MyEvent event) {
        // 处理符合条件的事件逻辑...
    }
}

# 4. 事件的继承

在Spring事件机制中,事件可以继承,子事件可以扩展父事件的属性和方法。这样,监听父事件的监听器也能够监听到子事件。

public class ParentEvent extends ApplicationEvent {
    //...
}

public class ChildEvent extends ParentEvent {
    //...
}

监听器可以监听父事件类型,同时也能够监听到子事件。

@Component
public class MyEventListener implements ApplicationListener<ParentEvent> {
    //...
}

通过使用Spring事件的高级特性,可以更灵活地处理事件。可以根据需要指定事件的处理顺序、实现异步处理、进行事件的过滤,甚至可以通过事件的继承来实现更复杂的逻辑。这些特性使得Spring事件机制更加强大和可扩展。

# 5. 泛型支持

Spring事件机制也支持泛型,使得事件的使用更加灵活和类型安全。通过在事件类和监听器上使用泛型,可以将事件和监听器与具体的数据类型关联起来。

首先,定义一个泛型事件类,可以将泛型参数作为事件类的属性类型。

public class GenericEvent<T> extends ApplicationEvent {
    private T data;

    public GenericEvent(Object source, T data) {
        super(source);
        this.data = data;
    }

    public T getData() {
        return data;
    }
}

然后,定义一个监听泛型事件的监听器。可以通过指定泛型参数来限制监听器只监听特定类型的事件。

@Component
public class GenericEventListener {

    @EventListener
    public <T> void handleGenericEvent(GenericEvent<Person> event) {
        Person person = event.getData();
        // 处理事件逻辑...
    }
}

通过使用泛型,可以实现更加通用和类型安全的事件处理。不同的事件类型可以使用不同的泛型参数,并且监听器也可以根据需求来监听特定类型的泛型事件。这样,可以更好地满足业务需求,提高代码的可复用性和可维护性。

# 四、Spring现有事件

Spring框架提供了一些现有的事件,用于处理与应用程序上下文、Bean生命周期和Web应用相关的事件。

# 1. ApplicationContext事件

在Spring中,ApplicationContext事件是与应用程序上下文相关的事件。它们包括:

  • ContextRefreshedEvent:当ApplicationContext被初始化或刷新时触发。可以在此事件中执行一些初始化操作。
  • ContextStartedEvent:当ApplicationContext被启动时触发。可以在此事件中执行一些启动操作。
  • ContextStoppedEvent:当ApplicationContext被停止时触发。可以在此事件中执行一些停止操作。
  • ContextClosedEvent:当ApplicationContext被关闭时触发。可以在此事件中执行一些清理操作。

# 2. Spring Boot事件

在Spring Boot中,除了Spring框架提供的事件之外,还有一些特定于Spring Boot的事件,用于处理与应用程序启动、配置和生命周期相关的事件。

以下是一些常见的Spring Boot事件:

  • ApplicationStartedEvent:当Spring Boot应用程序启动开始时触发的事件。可以在此事件中执行一些初始化操作。
  • ApplicationEnvironmentPreparedEvent:在Spring Boot应用程序环境准备完成后触发的事件。可以在此事件中对应用程序的环境进行一些自定义配置。
  • ApplicationPreparedEvent:在Spring Boot应用程序准备完成后触发的事件。可以在此事件中进行一些额外的配置和准备工作。
  • ApplicationReadyEvent:当Spring Boot应用程序完全启动并准备就绪时触发的事件。可以在此事件中执行一些启动后的操作。
  • ApplicationFailedEvent:当Spring Boot应用程序启动过程中发生错误时触发的事件。可以在此事件中处理错误并进行相应的处理。

# 3. Web应用事件

对于使用Spring进行Web应用开发的场景,还有一些与Web应用相关的事件。它们包括:

  • RequestHandledEvent:一个特定于Web的事件,通知所有bean HTTP请求已得到服务。此事件在请求完成后发布。此事件仅适用于使用Spring DispatcherServlet的Web应用程序。
  • ServletRequestHandledEvent:RequestHandledEvent的一个子类,用于添加Servlet特定的上下文信息。

# 五、事务绑定事件

# 1. @TransactionalEventListener注解

如果在事务方法中发送事件,比如:

    @Transactional
    public Customer createCustomer(User user) {
        User newUser = userRepository.save(user);
        final UserCreatedEvent event = new UserCreatedEvent(newUser);
        applicationEventPublisher.publishEvent(event);
        return newUser;
    }

事件接受处理如下:

@Component
public class UserCreatedEventListener {

    private final EmailService emailService;

    public UserCreatedEventListener(EmailService emailService) {
        this.emailService = emailService;
    }

    @EventListener
    public void processUserCreatedEvent(UserCreatedEvent event) {
        emailService.sendEmail(event.getUser().getEmail());
    }
}

此时有一个问题,那就是这两个功能还会再同一个事务中执行。如果用@Asnyc异步执行呢?则可能会出现事务出错了,但事件已经发送的情况。

@TransactionalEventListener注解可以解决上面的问题。使用@TransactionalEventListener注解来监听事务绑定事件。该注解可以将监听器与特定类型的事务绑定事件关联起来,以在事务的不同阶段触发相应的逻辑。

@TransactionalEventListener注解可以用于以下几个属性:

  • phase:指定事件的触发阶段,默认为TransactionPhase.AFTER_COMMIT,表示在事务成功提交后触发。
  • classes:指定要监听的事件类型。
  • fallbackExecution:指定是否在事务无法提交时也执行监听器,默认为false。
  • condition:指定监听器的条件表达式,满足条件时才会触发监听器。

TransactionPhase有如下值:

  • AFTER_COMMIT:默认设置,在事务提交成功后处理事件
  • BEFORE_COMMIT:在事务提交之前处理事件
  • AFTER_ROLLBACK:在事务回滚后执行
  • AFTER_COMPLETION:在事务完成后执行(不管是否成功)

示例代码如下所示:

@Component
public class TransactionCommitEventListener {

    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, classes = UserCreatedEvent.class)
    public void handleTransactionCommitEvent(UserCreatedEvent event) {
        // 处理事务提交事件逻辑
    }
}

通过如此处理,在事务提交成功后,再触发相关事件,就可以避免上面的问题。

# 2. 注意事项

如果你遇到这样的业务,操作B需要在操作A事务提交后去执行,那么TransactionalEventListener是一个很好地选择。

这里需要特别注意的一个点就是:当B操作有数据改动并持久化时,并希望在A操作的AFTER_COMMIT阶段执行,那么你需要将B事务声明为PROPAGATION_REQUIRES_NEW。这是因为A操作的事务提交后,事务资源可能仍然处于激活状态,如果B操作使用默认的PROPAGATION_REQUIRED的话,会直接加入到操作A的事务中,但是这时候事务A是不会再提交,结果就是程序写了修改和保存逻辑,但是数据库数据却没有发生变化,解决方案就是要明确的将操作B的事务设为PROPAGATION_REQUIRES_NEW。

# 六、总结

本文介绍了Spring事件的概念、基本使用和高级特性,以及Spring中现有的事件和事务绑定事件。通过使用Spring事件机制,可以实现组件之间的解耦、灵活的通信和动态的扩展,提高代码的可维护性和可测试性。

在基本使用中,我们学习了如何创建事件、发布事件和监听事件。通过定义事件类、使用ApplicationEventPublisher接口发布事件,并实现ApplicationListener接口监听事件,我们可以实现事件的传递和处理。

在高级特性中,我们了解了事件的顺序、异步处理、过滤和继承的功能。通过指定事件处理顺序、使用@Async注解实现异步处理、添加条件注解进行事件过滤,以及通过继承实现事件的扩展,我们可以更灵活地处理事件。

在现有事件中,我们介绍了与ApplicationContext、Spring Boot和Web应用相关的事件。这些事件提供了更高级别的抽象,使得开发人员可以更方便地处理与应用程序相关的事件。

最后,在事务绑定事件中,我们了解了使用@TransactionalEventListener注解来监听事务绑定事件。通过将监听器与特定类型的事务绑定事件关联起来,我们可以在事务的不同阶段执行相应的逻辑。

通过掌握Spring事件的使用和高级特性,我们可以更好地进行组件间的通信和处理,提高代码的灵活性和可维护性。同时,了解现有的事件和事务绑定事件,可以更好地控制和管理应用程序的行为和生命周期。

祝你变得更强!

编辑 (opens new window)
#Spring事件
上次更新: 2025/01/19
Spring容器:从依赖管理到注解配置全解析
Spring AOP的应用

← Spring容器:从依赖管理到注解配置全解析 Spring AOP的应用→

最近更新
01
Spring Boot版本新特性
09-15
02
Spring框架版本新特性
09-01
03
Spring Boot开发初体验
08-15
更多文章>
Theme by Vdoing | Copyright © 2018-2025 京ICP备2021021832号-2 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式