KOI技术-事件驱动编程(Sping后端)

1 "你日渐平庸,甘于平庸,将继续平庸。"------《以自己喜欢的方式过一生》

  1. "总是有人要赢的,那为什么不能是我呢?"------科比·布莱恩特

  2. "你那么憎恨那些人,和他们斗了那么久,最终却要变得和他们一样,人世间没有任何理想值得以这样的沉沦作为代价。"------马尔克斯《百年孤独》

  3. "如果结果不如你所愿,就在尘埃落定前奋力一搏。"------《夏目友人帐》

  4. "人有逆天之时,天无绝人之路。"------《醒世恒言》

  5. "有些事不是看到了希望才去坚持,而是因为坚持才会看到希望。"------《十宗罪》

  6. "维持现状意味着空耗你的努力和生命。"------纪伯伦
    Spring * 事件驱动编程

推荐

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> {

      @Override
      public void onApplicationEvent(DemoEvent event) {
          System.out.println(event.getName());
      }
    

    }

  • 定义事件发布(可不写,框架编程需要)

    @Component
    public class DemoPublisher implements ApplicationEventPublisherAware {

      private ApplicationEventPublisher applicationEventPublisher;
    
      @Override
      public 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 {

      @Autowired
      private ApplicationEventPublisher publisher;
    
      @Test
      public 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技术-事件驱动编程(前端)

相关推荐
字节流动21 分钟前
Android Java 版本的 MSAA OpenGL ES 多重采样
android·java·opengles
鹿屿二向箔1 小时前
基于SSM(Spring + Spring MVC + MyBatis)框架搭建一个病人跟踪信息管理系统
spring·mvc·mybatis
呜呼~225141 小时前
前后端数据交互
java·vue.js·spring boot·前端框架·intellij-idea·交互·css3
飞的肖2 小时前
从测试服务器手动热部署到生产环境的实现
java·服务器·系统架构
周伯通*2 小时前
策略模式以及优化
java·前端·策略模式
两点王爷2 小时前
Java读取csv文件内容,保存到sqlite数据库中
java·数据库·sqlite·csv
问道飞鱼2 小时前
【Springboot知识】Springboot进阶-实现CAS完整流程
java·spring boot·后端·cas
抓哇小菜鸡2 小时前
WebSocket
java·websocket
single5942 小时前
【c++笔试强训】(第四十五篇)
java·开发语言·数据结构·c++·算法
Q_19284999062 小时前
基于Spring Boot的电影网站系统
java·spring boot·后端