KOI技术-事件驱动编程(Sping后端)
1 “你日渐平庸,甘于平庸,将继续平庸。”——《以自己喜欢的方式过一生》
2. “总是有人要赢的,那为什么不能是我呢?”——科比·布莱恩特
3. “你那么憎恨那些人,和他们斗了那么久,最终却要变得和他们一样,人世间没有任何理想值得以这样的沉沦作为代价。”——马尔克斯《百年孤独》
4. “如果结果不如你所愿,就在尘埃落定前奋力一搏。”——《夏目友人帐》
5. “人有逆天之时,天无绝人之路。”——《醒世恒言》
6. “有些事不是看到了希望才去坚持,而是因为坚持才会看到希望。”——《十宗罪》
7. “维持现状意味着空耗你的努力和生命。”——纪伯伦
推荐
KOI技术-事件驱动编程(前端)
一. 概念
事件驱动编程是面向事件的,不同于传统的基于顺序的编程,它旨在当事件发生时,再采用行动进行处理的一种编程范式。它使得程序以松耦合的方式进行粘合,实现部分解耦。
二. 主要解决的问题
1.代码的松耦合
将系统复杂的功能拆分为多个部分,每个部分抽象为一个组件,组件与组件之间通过良好定义的接口进行通信;那么他们之间通信的触发若采用引入(依赖)调用的方式,便使得类之间产生了强关系,属于功能耦合,若把他们之间调用的触发抽象为事件,就能降低、解除组件之间的耦合关系。
事件驱动模型,实际上是将组件之间的耦合关系转移到了“事件(Event)”上,但是对于某个领域而言事件(Event)一般具有通用性并且不会频繁变更实现逻辑,所以事件驱动模型可以很好地实现组件之间的解耦。
2.异步编程的需要(MQ 主要用于分布式)
业务场景中,顺序、阻塞式地执行任务会遇到一些比较耗时的中间步骤,但是不希望整个流程都停下来等待这些中间步骤完成,而是触发一个异步操作然后继续执行当前任务,在收到异步操作处理完成的消息之后再执行相关的处理。
使用事件驱动模型实现异步任务的一般思路是:当遇到耗时较大、没有同步执行要求的操作时,针对这个操作触发一个事件,将这个事件加入到任务队列中,直到有一个进程(线程)能够获取并执行这个任务,才开始执行这个任务。
这里大家可能会想到MQ,MQ不就是干这个的吗,对,它确实是做这个的,但是是想一下,我就是一个单机系统或者我是一个底层编程框架,为了实现解耦异步我就要引入MQ,是不是有点大材小用,强制上车的意思。所以:事件编程适用于小范围或者小场景需求,但在框架编程中大量使用。
3.状态模型(状态机,日志记录)
这个场景理解起来比较简单,但是处理这种场景的方式却很多。 比如我们需要对实体状态的变更进行监控,(有没有想到禅道-项目管理中的最新动态),对请求的接口做一些日志记录,但日志有可能需要异步。这里大家可能会联想到AOP,确实在状态监控的实现上考虑到的简单方式就是切面变成,这里是想告诉大家,除了切面,事件驱动也可以实现。各有优劣。
三. 设计模式?
可能大家在查询资料或者学习过程中,会看到,事件编程或者状态管理时,会碰到设计模式中的 “观察者模式”,确实这个模式“很符合”这个场景,那问题来了,需要了解他吗? 我的建议是需要,为啥?懂了它,手写一个高大上的模式在项目上,岂不是更好,对于理解底层架构来说,也提供了思路,岂不更好。
观察者模式是使用频率较高的设计模式之一。 定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。是一种对象行为型模式。
观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。 看到这些名称有没有想到技术上的一些概念?MQ MVVM HODOOP 监听器
一些概念:
-
Subject(目标):被观察者,它是指被观察的对象。
-
ConcreteSubject(具体目标):具体目标是目标类的子类,通常它包含经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知。
-
Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法
update(),因此又称为抽象观察者。 -
ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观察者Observer
中定义的 update()方法。
图中涉及UML的关系要理解,图比较重要,看的懂才可以继续。:关联(实线实心箭头)泛化(继承 实线空心)实现(虚线空心)聚合(关联关系的一种,实现空心菱形)
四. JDK中的观察者模式(如何自行实现,不是从0开始)
观察者模式在 Java 语言中的地位非常重要。在 JDK 的 java.util 包中,提供了 Observable 类以及 Observer 接口,它们构成了 JDK 对观察者模式的支持(可以去查看下源码,写的比较严谨)。
这种方式不建议使用了,因为在jdk9之后废弃,且存在线程不安全问题,
**(推荐)**java.util.concurrent包中的ConcurrentHashMap和CopyOnWriteArrayList,以及java.util.EventListener相关的API来构建自己的观察者模式实现
五. Spring 的事件驱动编程(正文开始)
1. 概念
- 事件:ApplicationEvent 是所有事件对象的父类。ApplicationEvent 继承自 jdk 的 EventObject, 所有的事件都需要继承 ApplicationEvent, 并且通过 source 得到事件源。
Spring 也为我们提供了很多内置事件,ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、ContextClosedEvent、RequestHandledEvent。 - 事件监听:ApplicationListener,也就是观察者,继承自 jdk 的 EventListener,该类中只有一个方法
onApplicationEvent。当监听的事件发生后该方法会被执行。 - 事件源:ApplicationContext,ApplicationContext 是 Spring 中的核心容器,在事件监听中
ApplicationContext 可以作为事件的发布者,也就是事件源。因为 ApplicationContext 继承自
ApplicationEventPublisher。在 ApplicationEventPublisher
中定义了事件发布的方法:publishEvent(Object event) - 事件管理:ApplicationEventMulticaster,用于事件监听器的注册和事件的广播。监听器的注册就是通过它来实现的,它的作用是把Applicationcontext 发布的 Event 广播给它的监听器列表。
2. 核心类
- ApplicationEvent 事件类
- ApplicationListener 监听器泛型(事件类)
- @EventListener 注解同ApplicationListener 作用于方法上,参数是事件类
- ApplicationEventPublisher 自动发布事件的处理类,常用的,他是一个借口,自定义时可重写它
- ApplicationEventPublisherAware 接口类,用于业务处理中,它包含 setApplicationEventPublisher 的方法,用于指定ApplicationEventPublisher
- ApplicationEventMulticaster 用于事件监听器的注册和事件的广播,编程不涉及,但是需要了解下
3. 说一下 原理,懂了基本就OVER了,涉及源码,不懂暂时可以
1. 广播器 (类结构)
-
ApplicationEventMulticaster接口:提供了添加/移除监听器以及广播事件给监听器的行为。
-
AbstractApplicationEventMulticaster抽象类:提供了基础的监听器注册/移除以及查找能力。
-
SimpleApplicationEventMulticaster类:提供了事件广播功能。
2. 注册广播器和监听器
Spring容器初始化时, org.springframework.context.support.AbstractApplicationContext 在refresh()方法中,会进行广播器和监听器的注册。
- 初始化事件广播器(initApplicationEventMulticaster)
- 注册监听器(registerListeners)
- 事件广播
- publistEvent
- multicastEvent
4. 实操效果
- 定义事件
@EqualsAndHashCode(callSuper = true)
@Data
@Builder
public class DemoEvent extends ApplicationEvent {private String name;public DemoEvent(String source) {super(source);this.name = source;}public DemoEvent(Object source, Clock clock) {super(source, clock);}
}
- 定义事件监听
方式一:采用注解 适合业务编程@Component
public class DemoEventListener {@EventListener(DemoEvent.class)public void demoListener(DemoEvent event){System.out.println(event.getName());}
}方式二: 适合底层框架编程
public class DemoEventListenerIm implements ApplicationListener<DemoEvent> {@Overridepublic void onApplicationEvent(DemoEvent event) {System.out.println(event.getName());}
}
- 定义事件发布(可不写,框架编程需要)
@Component
public class DemoPublisher implements ApplicationEventPublisherAware {private ApplicationEventPublisher applicationEventPublisher;@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.applicationEventPublisher = applicationEventPublisher;}public void publishEvent(DemoEvent event) {System.out.println("publish event");applicationEventPublisher.publishEvent(event);}}
- 测试
@SpringBootTest(classes = EventApplication.class)
@RunWith(SpringRunner.class)
public class TestApplication {@Autowiredprivate ApplicationEventPublisher publisher;@Testpublic void demoEvenTest() {DemoEvent demoEvent = new DemoEvent("hello");publisher.publishEvent(demoEvent);System.out.println("laile");}
}
5. 其他注意点
-
事务监听器
@EnableTransactionManagement开启事务支持,@TransactionalEventListener标识事务监听器。
- 发布事件的操作必须在事务(@Transactional)内进行,否则监听器不会生效,也可以将fallbackExecution标志设置为true(@TransactionalEventListener(fallbackExecution = true))
- 可以配置在事务的哪个阶段来监听事务(默认在事务提交后监听),@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)。
-
异步支持
@EnableAsync开启异步支持,@Async标识监听器异步处理。开启异步执行后,方法的异常不会抛出,只能在方法内部处理。
-
条件监听
@EventListener(condition = “#event.message.contains(‘important’)”)
用于按照条件处理数据,可用与区分数据处理
-
监听器顺序
@Order控制多个监听器的执行顺序,值越小,监听器越先执行。
到这里您基本就了解了事件编程思路。 下面我们聊一聊前端的事件编程。KOI技术-事件驱动编程(前端)
相关文章:

KOI技术-事件驱动编程(Sping后端)
1 “你日渐平庸,甘于平庸,将继续平庸。”——《以自己喜欢的方式过一生》 2. “总是有人要赢的,那为什么不能是我呢?”——科比布莱恩特 3. “你那么憎恨那些人,和他们斗了那么久,最终却要变得和他们一样,…...

LVS 负载均衡原理 | 配置示例
注:本文为 “ LVS 负载均衡原理 | 配置” 相关文章合辑。 部分内容已过时,可以看看原理实现。 未整理去重。 使用 LVS 实现负载均衡原理及安装配置详解 posted on 2017-02-12 14:35 肖邦 linux 负载均衡集群是 load balance 集群的简写,翻…...
Hive分区再分桶表
在Hive中,数据通常是根据分区(partition)来组织的,但是对于大数据集,单层分区可能不够用,因此可以进一步细分为桶(bucket)。桶可以用于提供额外的并行处理和优化查询性能。在这种情况…...

从 Coding (Jenkinsfile) 到 Docker:全流程自动化部署 Spring Boot 实战指南(简化篇)
前言 本文记录使用 Coding (以 Jenkinsfile 为核心) 和 Docker 部署 Springboot 项目的过程,分享设置细节和一些注意问题。 1. 配置服务器环境 在实施此过程前,确保服务器已配置好 Docker、MySQL 和 Redis,可参考下列链接进行操作࿱…...
Linux官文转载-- Linux 内核代码风格
Warning 此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 这是一个简短的文档,描述了 linux 内核的首选代码风格。代码风格是因人而异的&a…...

Qt监控系统放大招/历经十几年迭代完善/多屏幕辅屏预览/多层级设备树/网络登录和回放
一、前言说明 近期对视频监控系统做了比较大的更新升级,主要就是三点,第一点就是增加了辅屏预览,这个也是好多个客户需要的功能,海康的iVMS-4200客户端就有这个功能,方便在多个屏幕打开不同的视频进行查看,…...

【贪心算法】贪心算法七
贪心算法七 1.整数替换2.俄罗斯套娃信封问题3.可被三整除的最大和4.距离相等的条形码5.重构字符串 点赞👍👍收藏🌟🌟关注💖💖 你的支持是对我最大的鼓励,我们一起努力吧!😃…...
LangChain教程 - 表达式语言 (LCEL) -构建智能链
系列文章索引 LangChain教程 - 系列文章 LangChain提供了一种灵活且强大的表达式语言 (LangChain Expression Language, LCEL),用于创建复杂的逻辑链。通过将不同的可运行对象组合起来,LCEL可以实现顺序链、嵌套链、并行链、路由以及动态构建等高级功能…...

使用Locust对Redis进行负载测试
1.安装环境 安装redis brew install redis 开启redis服务 brew services start redis 停止redis服务 brew services stop redis 安装Python库 pip install locust redis 2.编写脚本 loadTest.py # codingutf-8 import json import random import time import redis …...
HIVE数据仓库分层
1:为什么要分层 大多数情况下,我们完成的数据体系却是依赖复杂、层级混乱的。在不知不觉的情况下,我们可能会做出一套表依赖结构混乱,甚至出现循环依赖的数据体系。 我们需要一套行之有效的数据组织和管理方法来让我们的数据体系…...
数据结构与算法之动态规划: LeetCode 2407. 最长递增子序列 II (Ts版)
最长递增子序列 II https://leetcode.cn/problems/longest-increasing-subsequence-ii/description/ 描述 给你一个整数数组 nums 和一个整数 k找到 nums 中满足以下要求的最长子序列: 子序列 严格递增子序列中相邻元素的差值 不超过 k请你返回满足上述要求的 最…...
电子电气架构 --- 什么是自动驾驶技术中的域控制单元(DCU)?
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所谓鸡汤,要么蛊惑你认命,要么怂恿你拼命,但都是回避问题的根源,以现象替代逻辑,以情绪代替思考,把消极接受现实的懦弱,伪装成乐观面对不幸的…...
html5css3
1.html5新增语义化标签 <header><nav><article><section><aside><footer> 2.新增多媒体标签 视频<video>格式:map4,webm,ogg <video controls"controls" autoplay"autoplay" muted"mute…...

FPGA多路红外相机视频拼接输出,提供2套工程源码和技术支持
目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目我这里已有的红外相机图像处理解决方案本博已有的已有的FPGA视频拼接叠加融合方案 3、工程详细设计方案工程设计原理框图红外相机FDMA多路视频拼接算法FDMA图像缓存视…...

python实战(十二)——如何进行新词发现?
一、概念 新词发现是NLP的一个重要任务,旨在从大量的文本数据中自动识别和提取出未在词典中出现的新词或短语,这对于信息检索、文本挖掘、机器翻译等应用具有重要意义,因为新词往往包含了最新的知识和信息。 随着互联网的不断发展,…...

动手做计算机网络仿真实验入门学习
打开软件 work1 添加串行接口模块,先关电源,添加之后再开电源 自动选择连接 所有传输介质 自动连接 串行线 绿色是通的,红色是不通的。 显示接口。se是serial串行的简写。 Fa是fast ethernet的简写。 为计算机配置ip地址: 为服…...
完整的 FFmpeg 命令使用教程
FFmpeg 是一个开源的跨平台音视频处理工具,它能够处理几乎所有的视频、音频格式,并提供了强大的功能如格式转换、视频剪辑、合并、提取音频等。FFmpeg 通过命令行界面(CLI)操作,尽管有一些图形界面的前端工具ÿ…...
Leetcode 3405. Count the Number of Arrays with K Matching Adjacent Elements
Leetcode 3405. Count the Number of Arrays with K Matching Adjacent Elements 1. 解题思路2. 代码实现 题目链接:3405. Count the Number of Arrays with K Matching Adjacent Elements 1. 解题思路 这一题虽然是一道hard的题目,但是委实是有点名不…...

Springboot(五十六)SpringBoot3集成SkyWalking
这里我们将skywalking集成到Springboot中。 关于docker部署skyWalking的相关问题,请移步《docker(二十八)docker-compose部署链路追踪SkyWalking》 一:下载java-agents 先放一下skyWalking的官网下载地址 Downloads | Apache SkyWalking 其他的版本的 APM 地址(这个我不需…...

有没有免费提取音频的软件?音频编辑软件介绍!
出于工作和生活娱乐等原因,有时候我们需要把音频单独提取出来(比如歌曲伴奏、人声清唱等、乐器独奏等)。要提取音频必须借助音频处理软件,那么有没有免费提取音频的软件呢?下面我们将为大家介绍几款免费软件࿰…...

19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...