spring中ApplicationListener的使用小结

 更新时间:2024年07月08日 09:21:43   作者:孟秋与你  
ApplicationListener是spring提供的一个监听器,本文主要介绍了spring中ApplicationListener的使用小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

ApplicationListener 是spring提供的一个监听器,它可以实现一个简单的发布-订阅功能,用有点外行但最简单通俗的话来解释:监听到主业务在执行到了某个节点之后,在监听器里面做出相应的其它业务变更。下面我们具体看段代码,则能很快的理解

使用示例:

首先定义一个业务实体类,实体类定义字段、get set方法、构造函数

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor

/**
 * 模拟业务对象实体类
 * @author csdn:孟秋与你
 */
public class MyBizEntity {
    private String name;
    private Integer age;
}

再定义一个事件,事件继承ApplicationEvent

import org.springframework.context.ApplicationEvent;

/**
 * 自定义事件(继承ApplicationEvent)
 * @author csdn:孟秋与你
 */
public class MyEvent extends ApplicationEvent {


    public MyEvent(Object source) {
        super(source);
    }
    public MyEvent() {
        // java基础:如果父类只有有参构造 子类需要使用其它构造函数 必须在构造函数第一行调用super 因为子类也是调用父类的构造函数
        super(null);
        // do other
    }
}

定义一个监听器,实现ApplicationListener接口:

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * 监听事件
 */
@Component
public class MyApplicationListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {

        // 必须判断自己要的类型  因为会监听到所有继承ApplicationEvent的事件
        if (applicationEvent instanceof MyEvent) {
            Object source = applicationEvent.getSource();
            MyBizEntity bizEntity = (MyBizEntity) source;
            System.out.println(bizEntity.getName() + ":------------name");
        }

    }
}


写一个接口进行测试, 此时监听器就能打印输出了

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/test/listener")
@RestController
public class MainBizController {

    @Autowired
    private ApplicationContext context;

    @GetMapping
    public String test() {
        // do something
        
        // 模拟要传递的业务对象
        MyBizEntity bizEntity = new MyBizEntity("name",18);
        MyEvent event = new MyEvent(bizEntity);
        // 上下文 发布事件
        context.publishEvent(event);
        return "success";
    }
}


原理简析:

为什么发布了事件,监听器就能够监听到呢? 其实原理很简单,就是spring进行了一个朴实无华的直接调用, 我们来看看源码:

context.publishEvent默认是调用AbstractApplicationContext类的publishEvent方法,而publishEvent方法里面调用了SimpleApplicationEventMulticaster 类的multicastEvent方法。

tips: 为什么上下文有publishEvent方法 ?
因为ApplicationContext继承了ApplicationEventPublisher

在这里插入图片描述

SimpleApplicationEventMulticaster: 首先会获取所有实现了ApplicationListener的监听器 (get by type就可以获取到), 接着会执行 invokeListener方法

在这里插入图片描述

我们看看最后doInvokeListener 做了什么:

在这里插入图片描述

通过上面源码链路,我们不难发现 其实就是调用了publishEvent方法后,spring在我们不轻易能看到的地方 去调用了一下监听器的onApplicationEvent 方法而已,通过源码我们也可以看到 默认是同步调用(没有定义taskExecutor时), 本质上是一个解耦,把原本可能要写在一起的业务代码拆分了。

如何异步发送

通过源码可以看到 SimpleApplicationEventMulticaster类的multicastEvent方法,会先获取Executor ,如果有executor 则通过异步方式发送

所以问题就变成了这个executor如何才能获取到值。

在这里插入图片描述

可以看到该类有一个public的setTaskExecutor方法

在这里插入图片描述

所以我们可以直接将该类的实例作为一个bean给spring托管,代码如下

@Configuration
public class EventConfig {

    @Bean(name = "applicationEventMulticaster")
    public SimpleApplicationEventMulticaster simpleApplicationEventMulticaster(TaskExecutor taskExecutor) {
        SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
        eventMulticaster.setTaskExecutor(taskExecutor);
        return eventMulticaster;
    }
}

这里涉及到一个spring的基础知识,上面代码的参数是(TaskExecutor taskExecutor) 所以需要先有一个executor bean,代码示例如下:

@Configuration
public class AsyncInBootConfig {

    /** 核心线程池大小 */
    private int corePoolSize = 20;

    /**
     * 最大可创建的线程数
     */
    private int maxPoolSize = 50;

    /**
     * 队列最大长度
     */
    private int queueCapacity = 100;

    /**
     * 线程池维护线程所允许的空闲时间
     */
    private int keepAliveSeconds = 300;

    @Primary
    @Bean(name = "threadPool")
    /**
     * springboot 线程池方式
     */
    public ThreadPoolTaskExecutor threadPoolTaskExecutor()
    {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setMaxPoolSize(maxPoolSize);
        executor.setCorePoolSize(corePoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveSeconds);
        // 线程池对拒绝任务(无线程可用)的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}


这样在发布消息时,就会使用全局配置的这个threadPool线程池了

到此这篇关于spring中ApplicationListener的使用小结的文章就介绍到这了,更多相关spring ApplicationListener内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用filter实现url级别内存缓存示例

    使用filter实现url级别内存缓存示例

    这篇文章主要介绍了使用filter实现url级别内存缓存示例,只需要一个静态类,在filter中调用,也可以全部写到filt里面。可以根据查询参数分别缓存,需要的朋友可以参考下
    2014-03-03
  • IntelliJ IDEA之高效代码插件RainBow Brackets详解

    IntelliJ IDEA之高效代码插件RainBow Brackets详解

    这篇文章主要介绍了IntelliJ IDEA之高效代码插件RainBow Brackets详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • SpringBoot的DeferredResult案例:DeferredResult的超时处理方式

    SpringBoot的DeferredResult案例:DeferredResult的超时处理方式

    这篇文章主要介绍了SpringBoot的DeferredResult案例:DeferredResult的超时处理方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • SpringBoot项目鉴权的4种方式小结

    SpringBoot项目鉴权的4种方式小结

    本文主要介绍了SpringBoot项目鉴权的4种方式小结,包括传统AOP、拦截器、参数解析器和过滤器,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • SpringBoot单点登录实现过程详细分析

    SpringBoot单点登录实现过程详细分析

    这篇文章主要介绍了SpringBoot单点登录实现过程,单点登录英文全称Single Sign On,简称就是SSO。它的解释是:在多个应用系统中,只需要登录一次,就可以访问其他相互信任的应用系统
    2022-12-12
  • Java纯代码实现导出文件为压缩包

    Java纯代码实现导出文件为压缩包

    这篇文章主要为大家详细介绍了Java如何代码实现导出文件为压缩包,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-02-02
  • Springboot迁移到Micronaut实现过程详解

    Springboot迁移到Micronaut实现过程详解

    这篇文章主要为大家 介绍了Springboot迁移到Micronaut实现过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • Java 实战项目之诚途旅游系统的实现流程

    Java 实战项目之诚途旅游系统的实现流程

    读万卷书不如行万里路,只学书上的理论是远远不够的,只有在实战中才能获得能力的提升,本篇文章手把手带你用java+SpringBoot+Vue+maven+Mysql实现一个精美的物流管理系统,大家可以在过程中查缺补漏,提升水平
    2021-11-11
  • SpringBoot实现EMQ设备的上下线告警

    SpringBoot实现EMQ设备的上下线告警

    EMQX 的上下线系统消息通知功能在客户端连接成功或者客户端断开连接,需要实现设备的上下线状态监控,所以本文给大家介绍了如何通过SpringBoot实现EMQ设备的上下线告警,文中有详细的代码示例,需要的朋友可以参考下
    2023-10-10
  • 并发编程之Java内存模型锁的内存语义

    并发编程之Java内存模型锁的内存语义

    这篇文章主要介绍了并发编程之Java内存模型锁的内存语义,锁的作用是让临界区互斥执行,本文只要围绕锁的内存语义展开全文内容,需要的小伙伴可以参考一下
    2021-11-11

最新评论