Spring事件监听机制

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

例如:。


提示:以下是本篇文章正文内容,下面案例可供参考

一、观察者模式是什么?

在这里插入图片描述

二、发布订阅模式是什么?

观察者模式发布订阅模式是有一点点区别的,区别有以下几点:

  • 耦合度:
    观察者模式中,观察者直接与被观察者(主题)关联。被观察者通常有一个观察者列表,知道每个具体的观察者,并在状态变化时直接通知它们。
    发布订阅模式中,发布者(Publisher)和订阅者(Subscriber)之间通过一个中间媒介(通常是事件总线或调度器)解耦。发布者并不直接知道订阅者,只关心发布事件。
  • 通知方式:
    观察者模式中,被观察者会调用每个观察者的更新方法,通常是一个统一的接口。
    发布订阅模式中,事件总线负责将事件分发给所有订阅了该事件的订阅者,订阅者可以根据事件类型来过滤和处理事件。
  • 消息传递:
    观察者模式通常涉及一对一的通知,即被观察者只通知其已知的观察者。
    发布订阅模式允许一对多的消息传递,一个发布者可以有多个订阅者,而一个订阅者也可以订阅多个发布者。
  • 动态性:
    观察者模式的动态性较低,观察者通常在运行时就已经与被观察者关联。
    发布订阅模式更灵活,订阅者可以在运行时动态地订阅和取消订阅事件,无需修改发布者的代码。
  • 控制流:
    观察者模式通常在同步环境中使用,发布者直接调用观察者的更新方法。
    发布订阅模式可以支持异步处理,订阅者可以在不同的线程或进程中接收和处理事件。
  • 消息粒度:
    观察者模式通常关注特定对象的状态变化。
    发布订阅模式更倾向于处理更抽象的事件或消息,可能包含更丰富的信息。
  • 可扩展性:
    发布订阅模式更容易扩展,因为新的订阅者可以轻松加入,而不会影响现有发布者。
  • 应用场景:
    观察者模式适合于需要即时响应状态变化的场景,如UI组件与模型的同步。
    发布订阅模式适用于需要解耦和异步处理的大型系统或分布式系统。

三、Spring事件监听机制

0、应用场景

  • 解耦:
    1、当一个操作完成后需要执行一系列后续动作,但这些动作与其他业务逻辑无关时,使用事件监听可以避免直接耦合。例如,用户注册成功后发送验证邮件或短信。
    2、有一种情况,在给原系统进行架构升级时。发现有五六处甚至更多地方都用到了发短信的功能,但是发短信的功能是耦合的写到这五六个地方的。如果这个时候,发短信功能根据客户的需求进行修改,就需要改五六个地方。解决:将发短信的功能写成事件,这样只需要修改一次即可,防止出现漏改的情况。而且事件可以更加灵活的添加到其他功能模块中。
  • 异步处理:
    对于耗时的操作,可以将其包装为事件,然后异步处理,以避免阻塞主线程。例如,用户上传大文件后,发布一个处理文件的事件,后台服务异步处理上传的文件。
  • 模块间通信:
    不同模块或服务之间可以通过发布和监听事件来通信,而不必知道对方的具体实现。例如,订单系统创建订单后,库存系统可以通过监听订单创建事件来更新库存状态。
  • 事务补偿:
    在分布式事务中,如果主事务成功,可以发布一个事件来触发补偿事务,确保整体业务的一致性。

1、概述

Spring的事件监听机制是基于观察者模式实现的,它允许在Spring应用上下文中,组件之间通过发布和监听事件来进行异步通信。

2、组成部分

  1. 事件对象(Event Object):
    Spring提供了一个基础类ApplicationEvent,它是所有自定义事件的基础。你需要创建自己的事件类,通常继承自ApplicationEvent,并添加特定事件的数据。
  2. 事件监听器(Event Listener):
    定义监听器有两种方式:
    接口方式:实现ApplicationListener接口,该接口有一个onApplicationEvent方法,当监听到事件时,这个方法会被调用。
    注解方式:使用@EventListener注解在方法上,这个方法会处理特定类型的事件。
  3. 事件发布(Event Publishing):
    要发布事件,你可以通过ApplicationContextApplicationEventPublisher接口的publishEvent方法来发送事件实例。
  4. 事件广播(Event Broadcasting):
    Spring使用ApplicationEventMulticaster接口来广播事件。默认实现是SimpleApplicationEventMulticaster,它负责找到所有监听特定事件的bean,并调用它们的事件处理方法。
  5. 事件注册(Event Registration):
    当bean被Spring容器初始化时,如果它实现了ApplicationListener接口或包含了@EventListener注解的方法,那么它会被自动注册为事件监听器。
  6. 工作流程:
    发布事件:当某个bean需要通知其他bean发生了某些事情时,它创建一个事件对象并调用publishEvent方法。
    广播事件ApplicationEventMulticaster接收到事件后,遍历所有已注册的监听器,调用它们的onApplicationEvent方法或注解方法。
    处理事件:监听器接收到事件后,执行相应的业务逻辑。
  7. 应用场景:
    数据库连接关闭后通知其他组件。
    请求处理完成后执行清理任务。
    定期任务完成后的通知。
    应用启动或关闭时的初始化和清理操作。

3、流程图

在这里插入图片描述

4、类图

四、代码实现

1.事件发布器

首先,springframework.context是Spring框架的一个重要模块,它提供了与应用程序上下文相关的服务,包括组件扫描、依赖注入、事件发布、国际化和资源处理等功能。在Spring框架中,ApplicationContext是这个模块的核心接口,它是bean工厂的扩展,增加了加载配置元数据、事件发布以及与其他Spring特性集成的能力。
事件发布器类MyBean 实现了ApplicationEventPublisherAware接口,关于ApplicationEventPublisherAware接口,这是Spring框架提供的一个回调接口,允许任何实现了该接口的bean获取到ApplicationEventPublisher的引用。ApplicationEventPublisher接口用于发布应用程序事件,这些事件可以被其他bean监听和处理。当一个bean实现了ApplicationEventPublisherAware,Spring容器会在初始化该bean时自动调用其setApplicationEventPublisher()方法,传入事件发布器的实例。

事件发布器类MyBean 的代码如下(示例):

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;

@Service
public class MyBean implements ApplicationEventPublisherAware {

    private ApplicationEventPublisher publisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void someMethod() {
        // 在业务逻辑中,当需要触发一个事件时,可以使用publisher
        CustomEvent customEvent = new CustomEvent(this);
        publisher.publishEvent(customEvent);
    }
}

class CustomEvent extends ApplicationEvent {
    // 事件的具体实现
    // ...
}

2.创建事件类

代码如下(示例):

import org.springframework.context.ApplicationEvent;

import java.time.Clock;
import java.util.List;

/**
 * @author ZY.xxx
 * @date 20xx/xx/xx xx:xx
 * 作废事件
 **/
public class CancelEvent extends ApplicationEvent {

    private Param1 param1;
    private List<Param2> param2List;

    public CancelEvent(Object source) {
        super(source);
    }

    public CancelEvent(Object source, Param1 param1, List<Param2> param2List) {
        super(source);
        this.param1= param1;
        this.param2List= param2List;
    }

    // 两个变量参数的getter和setter方法
    // ...
}


3.创建事件监听类(注解的方式实现)

代码如下(示例):

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 1. @author ZY.xxx
 2. @date 20xx/xx/xx xx:xx
 3. xx事件监听器
 **/
@Component
public class EventHandler {
    @Autowired
    private XXXService xxxService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private CommonService commonService;

	@EventListener
    public void onEnvet(CommonEvent event) {
        //公共事件逻辑
        // ...
    }
    
	@EventListener
    public void onEnvet(CancelEvent event) {
        //取消事件逻辑
        // ...
        //监听器监听到事件的发布,可以获取到事件中的全部信息
        event.getParam1();
        event.getParam2List();
    }

@EventListener的注意点

@EventListener是Spring框架中用于事件监听的一个注解,它的主要作用是将一个方法标记为事件处理器,用于响应特定类型的事件。
@EventListener提供了一种声明式的事件处理方式,使得事件驱动的编程模型在Spring应用中变得简单和灵活

  1. 事件发布
    发布器发布后
  2. 事件处理
    Spring容器在初始化时,会扫描带有@EventListener注解的方法。这些方法必须属于Spring管理的bean(注入到spring上下文中的类)
    每个@EventListener注解的方法都会关联一个或多个事件类型。当事件被发布时,Spring会检查当前事件的类型是否与注解中指定的事件类型匹配。
  3. 条件触发
    @EventListenercondition属性允许通过SpEL表达式控制事件处理的条件。如果表达式评估结果为真,事件处理方法才会被执行。
  4. 异步处理、
    默认情况下,事件处理是同步的,这意味着事件处理器方法会在发布事件的线程中执行。但通过@Async注解,可以将事件处理转换为异步执行。
  5. 事件分组:
    使用@Order注解可以指定事件处理方法的执行顺序,较低的数字表示优先级较高。
  6. 性能优化:
    Spring 4.2及以上版本引入了事件多路复用(multi-casting),通过缓存事件处理器的引用来提高性能,避免每次事件发布时都要查找处理器。

3.创建事件监听类(实现ApplicationListener接口)

代码如下(示例):

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

public class CustomEventListener implements ApplicationListener<CancelEvent> {

    @Override
    public void onApplicationEvent(CancelEvent event) {
        // 在这里处理CancelEvent 
        System.out.println("Received CancelEvent : " + event.getMessage());
        // 实现你的业务逻辑
    }
}

4.应用

可以在项目的任何地方不在改动源代码的基础上异步的执行事件event的功能
代码如下(示例):

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

@Service
public class A implements B {

    @Override
    public void method1(Param param) {
    	//原逻辑代码
        CancelEvent cancelEvent= new CancelEvent(param.getID(), param, paramList);
        this.eventPublisher.publishEvent(cancelEvent);
    }
}

个人理解

  1. 使用时,先创建new一个事件对象。
  2. 注入时间发布器对象EventPublisher,这个类主要是实现了ApplicationEventPublisherAware(原理见上),调用发布器发布事件的方法,这样事件就可以被其他bean监听和处理。
  3. 事件监听器(打了@EventListener注解或者实现ApplicationListener接口的类)会立马监听到第2步发布的事件,来执行监听器中的业务逻辑。(实现了事件逻辑与原逻辑解耦、独立的对事件中的逻辑进行统一的修改)

总结

提示:这里对文章进行总结:
例如:。

  • 19
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值