Spring中基于事件监听驱动 和 线程池的异步任务

news/2024/11/28 19:29:57/

文章目录

  • 事件监听驱动 与 异步
    • 事件源
      • ApplicationContextAware接口
    • 发布事件
    • 事件实体
    • 监听事件
    • 实现异步
    • 注入綫程池
  • 事件驱动机制,与MQ消息队列比较

事件监听驱动 与 异步

事件监听驱动优点:解耦,将 事件和业务进行解耦,通过@Asyc注解可以实现异步

事件监听驱动优点:解耦,将 事件和业务进行解耦,通过@Asyc注解可以实现异步

我们监听事件之前要有事件源source,事件(Event),发布事件(publishEvent),然后才能到监听事件。

事件驱动机制是观察者模式(称发布订阅)具体实现,事件对象(Event)相当于被观察对象(Subject), 事件监听(EventListener) 相当于观察者(Observer)

事件源

实现ApplicationContextAware接口
重写setApplicationContext方法
获取ApplicationContext对象

public class FilePhysicalDeleteEventListener implements ApplicationContextAware {private ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}
}

ApplicationContextAware接口

ApplicationContext作用具体参考 https://blog.csdn.net/Pluto372/article/details/130139628

在Spring/SpringMVC中,我们拿到IOC容器无非有三种方式,那就是使用ApplicationContext接口下的三个实现类:ClassPathXmlApplicationContextFileSystemXmlApplicationContextAnnotationConfigApplicationContext
但是SpringBoot的强大让我们无需再配置xml文件,也因此我们无法通过上述方式拿到ApplicationContext对象,所以当在项目需要用到spring中的bean对象时,一般做法就是实现ApplicationContextAware接口,通过这个接口就可以获取到ApplicationContext对象,进入从ApplicationContext中获取所需要bean对象。

总结:通过ApplicationContextAware接口获取ApplicationContext对象,ApplicationContext可以获取IOC容器中的bean

发布事件

通过ApplicationContext对象发布

 private void physicalDeleteFileByStorageEngine(List<RPanFile> realFileRecords) {//映射为路径集合List<String> realFilePathList = realFileRecords.stream().map(RPanFile::getRealPath).collect(Collectors.toList());DeleteFileContext context = new DeleteFileContext();context.setRealFilePathList(realFilePathList);try {storageEngine.delete(context);} catch (IOException e) {//记录错误日志applicationContext.publishEvent(new ErrorLogEvent(this, "实体文件:" + JSON.toJSONString(realFilePathList) + ", 物理删除失败,请执行手动删除", RPanConstants.ZERO_LONG));}}

事件实体

事件实体需要继承ApplicationEvent对象

@Getter
@Setter
@EqualsAndHashCode
@ToString
public class ErrorLogEvent extends ApplicationEvent {/*** 错误日志的内容*/private String errorMsg;/*** 当前登录的用户ID*/private Long userId;public ErrorLogEvent(Object source, String errorMsg, Long userId) {super(source);this.errorMsg = errorMsg;this.userId = userId;}
}

监听事件

注解@EventListener(ErrorLogEvent.class)方式监听事件

@Component
public class ErrorLogEventListener {@Autowiredprivate IErrorLogService iErrorLogService;/*** 监听系统错误日志事件,并保存到数据库中** @param event*/@EventListener(ErrorLogEvent.class)     //监听这个事件@Async(value = "eventListenerTaskExecutor")public void saveErrorLog(ErrorLogEvent event){RPanErrorLog record = new RPanErrorLog();//保存到数据库,调用mp 方法iErrorLogService.save(record);}
}

实现异步

实现异步,并指定线程池任务执行器,value 为指定线程池执行器的 bean的名称

@Async(value = “eventListenerTaskExecutor”)

当 ErrorLogEvent 事件发生时,相关的处理方法将会以异步的方式执行,
并且将使用指定的任务执行器 “eventListenerTaskExecutor”。不阻塞主线程,提高响应。

public class ErrorLogEventListener {@Autowiredprivate IErrorLogService iErrorLogService;/*** 监听系统错误日志事件,并保存到数据库中** @param event*/@EventListener(ErrorLogEvent.class)     //监听这个事件@Async(value = "eventListenerTaskExecutor")public void saveErrorLog(ErrorLogEvent event){RPanErrorLog record = new RPanErrorLog();//保存到数据库,调用mp 方法iErrorLogService.save(record);}
}

注入綫程池

通过Configuration注解和Bean注解以配置类的方式注入线程池
,通过name属性指定bean的名称

@SpringBootConfiguration
public class TreadPoolConfig {// 注入bean// 任务线程池执行器@Bean(name = "eventListenerTaskExecutor")public ThreadPoolTaskExecutor eventListenerTaskExecutor(){ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
//        new FutureTask<>();taskExecutor.setCorePoolSize(10);taskExecutor.setMaxPoolSize(10);taskExecutor.setKeepAliveSeconds(200);taskExecutor.setQueueCapacity(2048);taskExecutor.setThreadNamePrefix("event-listener-thread");//拒绝策略// CallerRunsPolicy 既不抛弃任务也不抛出异常,直接使用主线程来执行此任务// abort 直接拒绝并抛异常// discard 丢弃不抛出异常// discardEldest 抛弃队列中等待最久的taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());return taskExecutor;}
}

事件驱动机制,与MQ消息队列比较

MQ驱动的作用:解耦、异步、削峰
优点:解耦,异步,削峰,消息不丢失,解决高并发消息
缺点:难维护

事件驱动机制:解耦、异步,做不到削峰。
优点:维护简单
缺点:大并发扛不住,适合单机环境,消息可能丢失,无法削峰

总结MQ的优点

  1. 异步解耦
  2. 应对高并发的消息
  3. 适用于分布式环境
  4. 消息不丢失
  5. 对消息进行 削峰

总结MQ的缺点:

  1. 分布式场景下引发的复杂问题,如分布式事务等。

http://www.ppmy.cn/news/1418546.html

相关文章

FMix: Enhancing Mixed Sample Data Augmentation 论文阅读

1 Abstract 近年来&#xff0c;混合样本数据增强&#xff08;Mixed Sample Data Augmentation&#xff0c;MSDA&#xff09;受到了越来越多的关注&#xff0c;出现了许多成功的变体&#xff0c;例如MixUp和CutMix。通过研究VAE在原始数据和增强数据上学习到的函数之间的互信息…

带头节点单向非循环链表的基本操作(c语言实现)

头节点 头节点是数据结构中的一个概念&#xff0c;特别是在链表结构中。 它通常被设置为链表的第一个节点之前的一个节点&#xff0c;其数据域一般不存储链表中的实际数据&#xff0c;而它的指针域则存储指向链表中第一个实际节点的指针。 头节点的主要作用如下&#xff1a;…

【HTML】HTML简介

参考资料&#xff1a;https://html.spec.whatwg.org/#introduction 在最初的五年&#xff08;1990-1995&#xff09;中&#xff0c;HTML经历了一系列修订和扩展&#xff0c;最初主要由欧洲核子研究组织&#xff08;CERN&#xff09;托管&#xff0c;随后由互联网工程任务组&am…

Java中的消息队列(如RabbitMQ、Kafka)是如何工作的?

消息队列&#xff08;Message Queue&#xff09;是一种通信方法&#xff0c;其中消息发送者和接收者通过队列进行异步通信。在Java中&#xff0c;有许多消息队列系统&#xff0c;如RabbitMQ、Kafka等&#xff0c;它们各自有自己的特点和适用场景。这里尽量以一种通用的方式解释…

nodejs安装常用命令

安装 Node.js 后&#xff0c;你可以在命令行中使用以下常用命令&#xff1a; node&#xff1a;启动 Node.js 的交互式解释器&#xff0c;可以直接在命令行中执行 JavaScript 代码。 npm install <package-name>&#xff1a;安装一个 Node.js 模块&#xff0c;<packag…

数据结构与算法的经典问题 — 背包问题

数据结构与算法 数据结构与算法是计算机科学中的两个核心概念&#xff0c;它们在软件开发和问题解决中起着至关重要的作用。 数据结构 数据结构是计算机中存储、组织和管理数据的方式&#xff0c;它能够帮助我们高效地访问和修改数据。不同的数据结构适用于不同类型的应用场…

服务器主机关机重启告警

提取时间段内系统操作命名&#xff0c;出现系统重启命令&#xff0c;若要出现及时联系确认 重启命令&#xff1a; reboot / init 6 / shutdown -r now&#xff08;现在重启命令&#xff09; 关机命令&#xff1a; init 0 / shutdown -h now&#xff08;关机&#…

C++类和对象中下篇

赋值运算符重载 运算符重载 C为了增强代码的可读性引入了运算符重载&#xff0c;运算符重载是具有特殊函数名的函数&#xff0c;也具有其返回值类型&#xff0c;函数名字以及参数列表&#xff0c;其返回值类型与参数列表与普通的函数类似。 函数名字为&#xff1a;关键字ope…