iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Spring事件发布与监听机制的用法示例
  • 539
分享到

Spring事件发布与监听机制的用法示例

2023-06-20 12:06:19 539人浏览 独家记忆
摘要

小编给大家分享一下spring事件发布与监听机制的用法示例,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、ApplicationContext 事件机制Appl

小编给大家分享一下spring事件发布与监听机制的用法示例,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

一、ApplicationContext 事件机制

ApplicationContext 事件机制采用观察者设计模式来实现,通过 ApplicationEvent 事件类和 ApplicationListener 监听器接口,可以实现 ApplicationContext 事件发布与处理。

每当 ApplicationContext 发布 ApplicationEvent 时,如果 Spring 容器中有 ApplicationListener bean,则监听器会被触发执行相应的处理。当然,ApplicationEvent 事件的发布需要显示触发,要么 Spring 显示触发,要么我们显示触发。

二、ApplicationListener 监听器

定义应用监听器需要实现的接口。此接口继承了 jdk 标准的事件监听器接口 EventListener,EventListener 接口是一个空的标记接口,推荐所有事件监听器必须要继承它。

package org.springframework.context;import java.util.EventListener;@FunctionalInterfacepublic interface ApplicationListener<E extends ApplicationEvent> extends EventListener {void onApplicationEvent(E event);}
package java.util;public interface EventListener {}

ApplicationListener 是个泛型接口,我们自定义此接口的实现类时,如果指定了泛型的具体事件类,那么只会监听此事件。如果不指定具体的泛型,则会监听 ApplicationEvent 抽象类的所有子类事件。

如下我们定义一个监听器,监听具体的事件,例如监听 ApplicationStartedEvent 事件。

package com.chenpi;import lombok.extern.slf4j.Slf4j;import org.springframework.boot.context.event.ApplicationStartedEvent;import org.springframework.context.ApplicationListener;import org.springframework.stereotype.Component;@Slf4j@Componentpublic class MyApplicationListener implements ApplicationListener<ApplicationStartedEvent> {    @Override    public void onApplicationEvent(ApplicationStartedEvent event) {        log.info(">>> MyApplicationListener:{}", event);    }}

启动服务,会发现在服务启动后,此监听器被触发了。

Spring事件发布与监听机制的用法示例

如果不指定具体的泛型类,则会监听 ApplicationEvent 抽象类的所有子类事件。如下所示:

package com.chenpi;import lombok.extern.slf4j.Slf4j;import org.springframework.context.ApplicationEvent;import org.springframework.context.ApplicationListener;import org.springframework.stereotype.Component;@Slf4j@Componentpublic class MyApplicationListener implements ApplicationListener {    @Override    public void onApplicationEvent(ApplicationEvent event) {        log.info(">>> MyApplicationListener:{}", event);    }}

Spring事件发布与监听机制的用法示例

注意,监听器类的 bean 要注入到 Spring 容器中,不然不会生效。一种是使用注解注入,例如 @Component。另外可以使用 SpringApplicationBuilder.listeners() 方法添加,不过这两种方式有区别的,看以下示例。

首先我们使用 @Component 注解方式,服务启动时,监视到了2个事件:

  • ApplicationStartedEvent

  • ApplicationReadyEvent

package com.chenpi;import lombok.extern.slf4j.Slf4j;import org.springframework.boot.context.event.SpringApplicationEvent;import org.springframework.context.ApplicationListener;import org.springframework.stereotype.Component;@Slf4j@Componentpublic class MyApplicationListener implements ApplicationListener<SpringApplicationEvent> {    @Override    public void onApplicationEvent(SpringApplicationEvent event) {        log.info(">>> MyApplicationListener:{}", event);    }}

Spring事件发布与监听机制的用法示例

而使用 SpringApplicationBuilder.listeners() 方法添加监听器,服务启动时,监听到了5个事件:

  • ApplicationEnvironmentPreparedEvent

  • ApplicationContextInitializedEvent

  • ApplicationPreparedEvent

  • ApplicationStartedEvent

  • ApplicationReadyEvent

package com.chenpi;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.builder.SpringApplicationBuilder;import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplicationpublic class Application {    public static void main(String[] args) {        // SpringApplication.run(Application.class, args);        SpringApplication app = new SpringApplicationBuilder(Application.class)                .listeners(new MyApplicationListener()).build();        app.run(args);    }}

Spring事件发布与监听机制的用法示例

其实这是和监听器 bean 注册的时机有关,@component 注解的监听器 bean 只有在 bean 初始化注册完后才能使用;而通过 SpringApplicationBuilder.listeners() 添加的监听器 bean 是在容器启动前,所以监听到的事件比较多。但是注意,这两个不要同时使用,不然监听器会重复执行两遍。

如果你想在监听器 bean 中注入其他 bean(例如 @Autowired),那最好是使用注解形式,因为如果太早发布监听器,可能其他 bean 还未初始化完成,可能会报错。

三、ApplicationEvent 事件

ApplicationEvent 是所有应用事件需要继承的抽象类。它继承了 EventObject 类,EventObject 是所有事件的根类,这个类有个 Object 类型的对象 source,代表事件源。所有继承它的类的构造函数都必须要显示传递这个事件源。

package org.springframework.context;import java.util.EventObject;public abstract class ApplicationEvent extends EventObject {private static final long serialVersionUID = 7099057708183571937L;// 发布事件的系统时间private final long timestamp;public ApplicationEvent(Object source) {super(source);this.timestamp = System.currentTimeMillis();}public final long getTimestamp() {return this.timestamp;}}
package java.util;public class EventObject implements java.io.Serializable {    private static final long serialVersionUID = 5516075349620653480L;    protected transient Object  source;    public EventObject(Object source) {        if (source == null)            throw new IllegalArgumentException("null source");        this.source = source;    }    public Object getSource() {        return source;    }    public String toString() {        return getClass().getName() + "[source=" + source + "]";    }}

在 Spring 中,比较重要的事件类是 SpringApplicationEvent。Spring 有一些内置的事件,当完成某种操作时会触发某些事件。这些内置事件继承 SpringApplicationEvent 抽象类。SpringApplicationEvent 继承 ApplicationEvent 并增加了字符串数组参数字段 args。

@SuppressWarnings("serial")public abstract class SpringApplicationEvent extends ApplicationEvent {private final String[] args;public SpringApplicationEvent(SpringApplication application, String[] args) {super(application);this.args = args;}public SpringApplication getSpringApplication() {return (SpringApplication) getSource();}public final String[] getArgs() {return this.args;}}

Spring事件发布与监听机制的用法示例

我们可以编写自己的监听器,然后监听这些事件,实现自己的业务逻辑。例如编写 ApplicationListener接口的实现类,监听 ContextStartedEvent 事件,当应用容器 ApplicationContext 启动时,会发布该事件,所以我们编写的监听器会被触发。

  • ContextRefreshedEvent:ApplicationContext 被初始化或刷新时,事件被发布。ConfigurableApplicationContext接口中的 refresh() 方法被调用也会触发事件发布。初始化是指所有的 Bean 被成功装载,后处理 Bean 被检测并激活,所有单例 Bean 被预实例化,ApplicationContext 容器已就绪可用。

  • ContextStartedEvent:应用程序上下文被刷新后,但在任何 ApplicationRunner 和 CommandLineRunner 被调用之前,发布此事件。

  • ApplicationReadyEvent:此事件会尽可能晚地被发布,以表明应用程序已准备好为请求提供服务。事件源是SpringApplication 本身,但是要注意修改它的内部状态,因为到那时所有初始化步骤都已经完成了。

  • ContextStoppedEvent:ConfigurableApplicationContext 接口的 stop() 被调用停止 ApplicationContext 时,事件被发布。

  • ContextClosedEvent:ConfigurableApplicationContext 接口的 close() 被调用关闭 ApplicationContext 时,事件被发布。注意,一个已关闭的上下文到达生命周期末端后,它不能被刷新或重启。

  • ApplicationFailedEvent:当应用启动失败后发布事件。

  • ApplicationEnvironmentPreparedEvent:事件是在 SpringApplication 启动时发布的,并且首次检查和修改 Environment 时,此时上 ApplicationContext 还没有创建。

  • ApplicationPreparedEvent:事件发布时,SpringApplication 正在启动,ApplicationContext 已经完全准备好,但没有刷新。在这个阶段,将加载 bean definitions 并准备使用 Environment。

  • RequestHandledEvent:这是一个 WEB 事件,只能应用于使用 DispatcherServlet 的 Web 应用。在使用 Spring 作为前端mvc 控制器时,当 Spring 处理用户请求结束后,系统会自动触发该事件。

四、自定义事件和监听器

前面介绍了自定义监听器,然后监听 Spring 原有的事件。下面介绍自定义事件和自定义监听器,然后在程序中发布事件,触发监听器执行,实现自己的业务逻辑。

首先自定义事件,继承 ApplicationEvent,当然事件可以自定义自己的属性。

package com.chenpi;import lombok.Getter;import lombok.Setter;import lombok.ToString;import org.springframework.context.ApplicationEvent;@Getter@Setterpublic class MyApplicationEvent extends ApplicationEvent {    // 事件可以增加自己的属性    private String myField;    public MyApplicationEvent(Object source, String myField) {        // 绑定事件源        super(source);        this.myField = myField;    }    @Override    public String toString() {        return "MyApplicationEvent{" + "myField='" + myField + '\'' + ", source=" + source + '}';    }}

然后自定义监听器,监听我们自定义的事件。

package com.chenpi;import lombok.extern.slf4j.Slf4j;import org.springframework.context.ApplicationListener;@Slf4jpublic class MyApplicationListener implements ApplicationListener<MyApplicationEvent> {    @Override    public void onApplicationEvent(MyApplicationEvent event) {        log.info(">>> MyApplicationListener:{}", event);    }}

注册监听器和发布事件。注册监听器上面讲解了有两种方式。事件的发布可以通过 ApplicationEventPublisher.publishEvent() 方法。此处演示直接用 configurableApplicationContext 发布,它实现了 ApplicationEventPublisher 接口。

package com.chenpi;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.builder.SpringApplicationBuilder;import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplicationpublic class Application {    public static void main(String[] args) {        // SpringApplication.run(Application.class, args);        // 注册监听器        SpringApplication app = new SpringApplicationBuilder(Application.class)                .listeners(new MyApplicationListener()).build();        ConfigurableApplicationContext configurableApplicationContext = app.run(args);        // 方便演示,在项目启动后发布事件,当然也可以在其他操作和其他时间点发布事件        configurableApplicationContext                .publishEvent(new MyApplicationEvent("我是事件源,项目启动成功后发布事件", "我是自定义事件属性"));    }}

启动服务,结果显示确实监听到发布的事件了。

2021-06-26 16:15:09.584  INFO 10992 --- [           main] o.s.b.w.embedded.Tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (Http) with context path ''

2021-06-26 16:15:09.601  INFO 10992 --- [           main] com.chenpi.Application                   : Started Application in 2.563 seconds (JVM running for 4.012)

2021-06-26 16:15:09.606  INFO 10992 --- [           main] com.chenpi.MyApplicationListener         : >>> MyApplicationListener:MyApplicationEvent{myField='我是自定义事件属性', source=我是事件源,项目启动成功后发布事件}

事件监听机制能达到分发,解耦效果。例如可以在业务类中发布事件,让监听在此事件的监听器执行自己的业务处理。例如:

package com.chenpi;import org.springframework.context.ApplicationEventPublisher;import org.springframework.context.ApplicationEventPublisherAware;import org.springframework.stereotype.Service;@Servicepublic class MyService implements ApplicationEventPublisherAware {    private ApplicationEventPublisher applicationEventPublisher;    @Override    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {        this.applicationEventPublisher = applicationEventPublisher;    }    public void testEvent() {        applicationEventPublisher                .publishEvent(new MyApplicationEvent("我是事件源", "我是自定义事件属性"));    }}

五、注解式监听器

除了实现 ApplicationListener 接口创建监听器外,Spring 还提供了注解 @EventListener 来创建监听器。

package com.chenpi;import org.springframework.context.event.EventListener;import org.springframework.stereotype.Component;import lombok.extern.slf4j.Slf4j;@Slf4j@Componentpublic class MyApplicationListener01 {    @EventListener    public void onApplicationEvent(MyApplicationEvent event) {        log.info(">>> MyApplicationListener:{}", event);    }}

而且注解还可以通过条件过滤只监听指定条件的事件。例如事件的 myField 属性的值等于"陈皮"的事件。

package com.chenpi;import org.springframework.context.event.EventListener;import org.springframework.stereotype.Component;import lombok.extern.slf4j.Slf4j;@Slf4j@Componentpublic class MyApplicationListener01 {    @EventListener(condition = "#event.myField.equals('陈皮')")    public void onApplicationEvent(MyApplicationEvent event) {        log.info(">>> MyApplicationListener:{}", event);    }}

还可以在同一个类中定义多个监听,对同一个事件的不同监听还可以指定顺序。order 值越小越先执行。

package com.chenpi;import org.springframework.context.event.EventListener;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;import lombok.extern.slf4j.Slf4j;@Slf4j@Componentpublic class MyApplicationListener01 {    @Order(2)    @EventListener    public void onApplicationEvent(MyApplicationEvent event) {        log.info(">>> onApplicationEvent order=2:{}", event);    }    @Order(1)    @EventListener    public void onApplicationEvent01(MyApplicationEvent event) {        log.info(">>> onApplicationEvent order=1:{}", event);    }    @EventListener    public void otherEvent(YourApplicationEvent event) {        log.info(">>> otherEvent:{}", event);    }}

执行结果如下:

>>> onApplicationEvent order=1:MyApplicationEvent{myField='陈皮', source=我是事件源}

>>> onApplicationEvent order=2:MyApplicationEvent{myField='陈皮', source=我是事件源}

>>> otherEvent:MyApplicationEvent{myField='我是自定义事件属性01', source=我是事件源01}

事件的监听处理是同步的,如下:

package com.chenpi;import lombok.extern.slf4j.Slf4j;import org.springframework.context.ApplicationEventPublisher;import org.springframework.context.ApplicationEventPublisherAware;import org.springframework.stereotype.Service;@Service@Slf4jpublic class MyService implements ApplicationEventPublisherAware {    private ApplicationEventPublisher applicationEventPublisher;    @Override    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {        this.applicationEventPublisher = applicationEventPublisher;    }    public void testEvent() {        log.info(">>> testEvent begin");        applicationEventPublisher.publishEvent(new MyApplicationEvent("我是事件源", "陈皮"));        applicationEventPublisher.publishEvent(new YourApplicationEvent("我是事件源01", "我是自定义事件属性01"));        log.info(">>> testEvent end");    }}

执行结果如下:

2021-06-26 20:34:27.990  INFO 12936 --- [NIO-8081-exec-1] com.chenpi.MyService                     : >>> testEvent begin

2021-06-26 20:34:27.990  INFO 12936 --- [nio-8081-exec-1] com.chenpi.MyApplicationListener01       : >>> onApplicationEvent order=1:MyApplicationEvent{myField='陈皮', source=我是事件源}

2021-06-26 20:34:27.991  INFO 12936 --- [nio-8081-exec-1] com.chenpi.MyApplicationListener01       : >>> onApplicationEvent order=2:MyApplicationEvent{myField='陈皮', source=我是事件源}

2021-06-26 20:34:27.992  INFO 12936 --- [nio-8081-exec-1] com.chenpi.MyApplicationListener01       : >>> otherEvent:MyApplicationEvent{myField='我是自定义事件属性01', source=我是事件源01}

2021-06-26 20:34:27.992  INFO 12936 --- [nio-8081-exec-1] com.chenpi.MyService                     : >>> testEvent end

不过,我们也可以显示指定异步方式去执行监听器,记得在服务添加 @EnableAsync 注解开启异步注解。

package com.chenpi;import org.springframework.context.event.EventListener;import org.springframework.core.annotation.Order;import org.springframework.scheduling.annotation.Async;import org.springframework.stereotype.Component;import lombok.extern.slf4j.Slf4j;@Slf4j@Componentpublic class MyApplicationListener01 {    @Async    @Order(2)    @EventListener    public void onApplicationEvent(MyApplicationEvent event) {        log.info(">>> onApplicationEvent order=2:{}", event);    }    @Order(1)    @EventListener    public void onApplicationEvent01(MyApplicationEvent event) {        log.info(">>> onApplicationEvent order=1:{}", event);    }    @Async    @EventListener    public void otherEvent(YourApplicationEvent event) {        log.info(">>> otherEvent:{}", event);    }}

执行结果如下,注意打印的线程名。

2021-06-26 20:37:04.807  INFO 9092 --- [nio-8081-exec-1] com.chenpi.MyService                     : >>> testEvent begin

2021-06-26 20:37:04.819  INFO 9092 --- [nio-8081-exec-1] com.chenpi.MyApplicationListener01       : >>> onApplicationEvent order=1:MyApplicationEvent{myField='陈皮', source=我是事件源}

2021-06-26 20:37:04.831  INFO 9092 --- [         task-1] com.chenpi.MyApplicationListener01       : >>> onApplicationEvent order=2:MyApplicationEvent{myField='陈皮', source=我是事件源}

2021-06-26 20:37:04.831  INFO 9092 --- [nio-8081-exec-1] com.chenpi.MyService                     : >>> testEvent end

2021-06-26 20:37:04.831  INFO 9092 --- [         task-2] com.chenpi.MyApplicationListener01       : >>> otherEvent:MyApplicationEvent{myField='我是自定义事件属性01', source=我是事件源01}

以上是“Spring事件发布与监听机制的用法示例”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网精选频道!

--结束END--

本文标题: Spring事件发布与监听机制的用法示例

本文链接: https://www.lsjlt.com/news/296588.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Spring事件发布与监听机制的用法示例
    小编给大家分享一下Spring事件发布与监听机制的用法示例,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、ApplicationContext 事件机制Appl...
    99+
    2023-06-20
  • 详解Spring事件发布与监听机制
    目录一、ApplicationContext 事件机制二、ApplicationListener 监听器三、ApplicationEvent 事件四、自定义事件和监听器五、注解式监听...
    99+
    2022-11-12
  • 解析Spring事件发布与监听机制
    前言 Spring 提供了 ApplicationContext 事件机制,可以发布和监听事件,这个特性非常有用。 Spring 内置了一些事件和监听器,例如在 Spring 容器启...
    99+
    2022-11-12
  • Spring的事件发布与监听方式是什么
    本篇内容介绍了“Spring的事件发布与监听方式是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!事件主要代码在org.springfra...
    99+
    2023-07-05
  • SpringBoot事件发布和监听的示例分析
    这篇文章主要介绍SpringBoot事件发布和监听的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!概述ApplicationEvent以及Listener是Spring为我们提供的一个事件监听、订阅的实现,内...
    99+
    2023-06-25
  • Flex事件机制中Flex事件分发和监听的示例分析
    这篇文章给大家分享的是有关Flex事件机制中Flex事件分发和监听的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。什么是Flex事件机制Flex事件可以看作是一种触发机制,当满足了一定的条件后,会触发这个...
    99+
    2023-06-17
  • C#开发中事件与委托机制的示例分析
    这篇文章给大家分享的是有关C#开发中事件与委托机制的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。概述C#中的委托类似于C或C++中的函数指针。使用委托使程序员可以将方法引用封装在委托对象内。然后可以将该...
    99+
    2023-06-17
  • Android中自定义view中事件分发机制与处理的示例分析
    这篇文章将为大家详细讲解有关Android中自定义view中事件分发机制与处理的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。题引事件只有一个,多个人想要处理,处理的对象不是我们想给的对象就是事件...
    99+
    2023-06-25
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作