欢迎访问shiker.tech

请允许在我们的网站上展示广告

您似乎使用了广告拦截器,请关闭广告拦截器。我们的网站依靠广告获取资金。

【译文】spring event 使用介绍
(last modified Jun 26, 2023, 12:31 PM )
by
侧边栏壁纸
  • 累计撰写 176 篇文章
  • 累计创建 61 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

【译文】spring event 使用介绍

橙序员
2022-12-25 / 0 评论 / 0 点赞 / 525 阅读 / 2,180 字 / 正在检测百度是否收录... 正在检测必应是否收录...
文章摘要(AI生成)

本文讨论了如何在Spring中使用事件,介绍了事件发布和监听的基本原则。在旧版本的Spring中,事件类需要扩展ApplicationEvent类,而在4.2版本之后,则不再需要。发布者需要注入一个ApplicationEventPublisher对象,而监听器需要实现ApplicationListener接口。

文章还介绍了如何自定义事件,并给出了一个简单的示例,包括一个自定义事件类和一个事件发布者。发布者通过注入ApplicationEventPublisher并使用publishEvent() API来发布事件。

该文章的原文链接:https://www.baeldung.com/spring-events

原文地址:https://www.baeldung.com/spring-events

1.概述

在本教程中,我们将讨论如何在 Spring 中使用事件。

事件是框架中比较容易被忽视的功能之一,但也是比较有用的功能之一。与 Spring 中的许多其他事物一样,事件发布是ApplicationContext提供的功能之一。

有一些简单的指导原则可以遵循:

如果我们使用 Spring Framework 4.2 之前的版本,事件类应该扩展ApplicationEvent 。从 4.2 版本开始,事件类不再需要扩展 ApplicationEvent 类。
发布者应该注入一个ApplicationEventPublisher对象。
侦听器应实现ApplicationListener接口。

2.自定义事件

Spring 允许我们创建和发布默认情况下同步的自定义事件。这有一些优点,例如监听器能够参与发布者的事务上下文。

2.1. 一个简单的应用程序事件

让我们创建一个简单的事件类——只是一个存储事件数据的占位符。

在这种情况下,事件类包含一个 String 消息:

public class CustomSpringEvent extends ApplicationEvent {
    private String message;

    public CustomSpringEvent(Object source, String message) {
        super(source);
        this.message = message;
    }
    public String getMessage() {
        return message;
    }
}

2.2. publisher

现在让我们创建该事件的发布者。发布者构建事件对象并将其发布给正在收听的任何人。

要发布事件,发布者只需注入ApplicationEventPublisher并使用publishEvent() API

@Component
public class CustomSpringEventPublisher {
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    public void publishCustomEvent(final String message) {
        System.out.println("Publishing custom event. ");
        CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message);
        applicationEventPublisher.publishEvent(customSpringEvent);
    }
}

或者,发布者类可以实现ApplicationEventPublisherAware接口,这也会在应用程序启动时注入事件发布者。通常,使用@Autowire注入发布者会更简单。

从 Spring Framework 4.2 开始, ApplicationEventPublisher接口为 接受任何对象作为事件的publishEvent(Object event)方法提供了一个新的重载。因此,Spring事件不再需要扩展ApplicationEvent类。

2.3. listener

最后,让我们创建监听器。

监听器的唯一要求是成为一个 bean 并实现ApplicationListener接口:

@Component
public class CustomSpringEventListener implements ApplicationListener<CustomSpringEvent> {
    @Override
    public void onApplicationEvent(CustomSpringEvent event) {
        System.out.println("Received spring custom event - " + event.getMessage());
    }
}

请注意我们的自定义侦听器是如何使用自定义事件的通用类型进行参数化的,这使得onApplicationEvent()方法是类型安全的。这也避免了必须检查对象是否是特定事件类的实例并强制转换它。

而且,正如已经讨论过的(默认情况下Spring 事件是同步的),doStuffAndPublishAnEvent()方法会阻塞,直到所有侦听器完成对事件的处理。

3.创建异步事件

在某些情况下,同步发布事件并不是我们真正想要的——我们可能需要异步处理我们的事件。

我们可以通过使用执行程序创建一个ApplicationEventMulticaster bean在配置中打开它。

出于我们的目的,SimpleAsyncTaskExecutor运行良好:

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

事件、发布者和监听器的实现与以前相同,但现在监听器将在单独的线程中异步处理事件。

4.现有框架事件

Spring 本身发布了各种开箱即用的事件。例如,ApplicationContext将触发各种框架事件:ContextRefreshedEventContextStartedEventRequestHandledEvent等。

这些事件为应用程序开发人员提供了一个选项,可以挂钩应用程序的生命周期和上下文,并在需要时添加他们自己的自定义逻辑。

这是侦听上下文刷新的侦听器的快速示例:

public class ContextRefreshedListener 
  implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent cse) {
        System.out.println("Handling context re-freshed event. ");
    }
}

要了解有关现有框架事件的更多信息,请在此处查看我们的下一个教程。

5.注解驱动的事件监听器

从 Spring 4.2 开始,事件侦听器不需要是实现ApplicationListener接口的 bean——它可以通过@EventListener注释在托管 bean 的任何公共方法上注册:

@Component
public class AnnotationDrivenEventListener {
    @EventListener
    public void handleContextStart(ContextStartedEvent cse) {
        System.out.println("Handling context started event.");
    }
}

和以前一样,方法签名声明它使用的事件类型。

默认情况下,侦听器是同步调用的。但是,我们可以通过添加@Async注解轻松使其异步。我们只需要记住在应用程序中启用异步支持。

6.泛型支持

也可以使用事件类型中的泛型信息来分派事件。

6.1. 通用应用程序事件

让我们创建一个通用事件类型。

在我们的示例中,事件类包含任何内容和成功状态指示器:

public class GenericSpringEvent<T> {
    private T what;
    protected boolean success;

    public GenericSpringEvent(T what, boolean success) {
        this.what = what;
        this.success = success;
    }
    // ... standard getters
}

请注意GenericSpringEventCustomSpringEvent之间的区别。我们现在可以灵活地发布任意事件,并且不再需要从ApplicationEvent扩展。

6.2. listener

现在让我们创建该事件的侦听器。

我们可以像以前一样通过实现ApplicationListener接口来定义监听器:

@Component
public class GenericSpringEventListener 
  implements ApplicationListener<GenericSpringEvent<String>> {
    @Override
    public void onApplicationEvent(@NonNull GenericSpringEvent<String> event) {
        System.out.println("Received spring generic event - " + event.getWhat());
    }
}

但不幸的是,这个定义要求我们从ApplicationEvent类继承GenericSpringEvent 。因此,对于本教程,我们将使用之前讨论过的注解驱动的事件侦听器。

也可以通过在@EventListener注释上定义布尔 SpEL 表达式来使事件侦听器有条件。

在这种情况下,事件处理程序只会在 String 的GenericSpringEvent成功时被调用:

@Component
public class AnnotationDrivenEventListener {
    @EventListener(condition = "#event.success")
    public void handleSuccessful(GenericSpringEvent<String> event) {
        System.out.println("Handling generic event (conditional).");
    }
}

Spring 表达式语言 (SpEL)是一种功能强大的表达式语言,在另一个教程中有详细介绍。

6.3. publisher

事件发布者与上面描述的类似。但是由于类型擦除,我们需要发布一个事件来解析我们将过滤的泛型参数,例如,class GenericStringSpringEvent extends GenericSpringEvent<String>

此外,还有一种发布事件的替代方法。如果我们从使用@EventListener注释的方法返回非空值作为结果,Spring Framework 会将该结果作为新事件发送给我们。此外,我们可以通过将事件处理结果返回到集合中来发布多个新事件。

7.交易绑定事件

本节介绍如何使用@TransactionalEventListener注释。要了解有关事务管理的更多信息,请查看Transactions With Spring and JPA

从 Spring 4.2 开始,该框架提供了一个新的@TransactionalEventListener注解,它是@EventListener的扩展,允许将事件的侦听器绑定到事务的一个阶段。

可以绑定到以下事务阶段:

AFTER_COMMIT(默认)用于在事务成功完成时触发事件。
AFTER_ROLLBACK – 如果事务已经回滚
AFTER_COMPLETION – 如果事务已完成(AFTER_COMMIT和AFTER_ROLLBACK的别名)
BEFORE_COMMIT用于在事务提交之前立即触发事件。
下面是一个事务性事件侦听器的简单示例:

@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void handleCustom(CustomSpringEvent event) {
    System.out.println("Handling event inside a transaction BEFORE COMMIT.");
}

仅当存在事件生产者正在运行且即将提交的事务时,才会调用此侦听器。

如果没有事务在运行,则根本不会发送事件,除非我们通过将fallbackExecution属性设置为true来覆盖它。

8.结论

在这篇简短的文章中,我们回顾了在 Spring 中处理事件的基础知识,包括创建一个简单的自定义事件、发布它然后在侦听器中处理它。

我们还简要了解了如何在配置中启用事件的异步处理。

然后我们了解了 Spring 4.2 中引入的改进,例如注释驱动的侦听器、更好的泛型支持和事件绑定到事务阶段。

与往常一样,本文中提供的代码可在 GitHub 上获得。这是一个基于 Maven 的项目,因此它应该很容易导入并按原样运行。

0

评论区