Spring 事件(Spring Events)是 Spring 框架中的一个特性,它允许应用程序中的各个部分之间进行松耦合的通信。在 Spring 中,事件通常由事件发布者发布,然后由事件监听器监听和处理。这种模型使得不同部分的逻辑可以相互独立,降低它们之间的耦合度,同时也提高了代码的可维护性和可扩展性。

SpringEvent 核心类介绍

在 Spring 框架中,事件(Event)是一种用于在应用程序中处理消息和通知的机制。当某个特定的事件发生时,应用程序中的其他部分可以监听并作出相应的响应。以下是一些与 Spring 事件相关的主要对象:

  1. ApplicationEvent类:
    ApplicationEvent 是 Spring 事件体系的基类,用于表示应用程序中发生的事件。开发人员可以根据需要创建自定义的 ApplicationEvent 子类来表示特定类型的事件。
  2. ApplicationEventPublisher接口:
    ApplicationEventPublisher 是一个接口,定义了用于发布事件的方法。通过实现该接口,应用程序的各个部分可以发布事件,通知其他部分发生了特定的事件。
  3. ApplicationListener接口
    ApplicationListener 是一个接口,用于监听应用程序中发布的事件。通过实现该接口,并指定要监听的事件类型,开发人员可以编写事件监听器来处理特定类型的事件。
  4. @EventListener 注解:
    @EventListener 是一个注解,用于标记方法作为事件监听器。通过在方法上添加 @EventListener 注解,并指定要监听的事件类型,开发人员可以将方法注册为事件监听器,当相应的事件发生时,被标记的方法将被调用。
  5. ContextRefreshedEvent
    ContextRefreshedEvent 是 Spring 框架中的一个内置事件,表示应用程序上下文被初始化或刷新的事件。可以通过监听该事件来执行一些初始化操作。
  6. PayloadApplicationEvent
    PayloadApplicationEvent 是 ApplicationEvent 的一个实现,它允许将一个对象作为事件的负载(payload),这样监听器可以直接访问该负载对象。

这些对象构成了 Spring 框架中事件驱动编程的基本组成部分,开发人员可以利用它们来实现事件的发布和监听,从而实现应用程序内部各个部分之间的解耦和通信。

Spring Event 案例演示(3个类快速入门)

定义一个事件

首先需要定义一个自定义事件 CustomEvent,继承ApplicationEvent,让当前CustomEvent类变成一个事件类。同时事件本身自定义了2个参数 userName,age

import lombok.Getter;
import lombok.Setter;
import org.springframework.context.ApplicationEvent;

import java.time.Clock;

/**
 * @author : zanglikun
 * @date : 2024/6/16 上午11:38
 * @desc : Copyright © zanglikun.com 
 * 定一个类CustomEvent 继承ApplicationEvent,让当前CustomEvent类变成一个事件类
 */
public class CustomEvent extends ApplicationEvent {

    @Getter
    @Setter
    private String userName;

    @Getter
    @Setter
    private Integer age;

    // 继承ApplicationEvent必须要实现的方法
    public CustomEvent(Object source) {
        super(source);
    }

    // 继承ApplicationEvent必须要实现的方法
    public CustomEvent(Object source, Clock clock) {
        super(source, clock);
    }
}

创建事件监听器:

接下来,自定义一个事件监听器 CustomEventListener,用于监听刚才定义的CustomEvent事件,并在监听到事件的onApplicationEvent方法执行了发送QQ消息的逻辑。

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * @author : zanglikun
 * @date : 2024/6/16 上午11:46
 * @desc : Copyright © zanglikun.com 实现ApplicationListener参数指定CustomEvent,
 * 用来实现onApplicationEvent来执行对事件的处理
 */
@Slf4j
@Component // 不可省略
public class CustomEventListener implements ApplicationListener<CustomEvent> {

    @Override
    public void onApplicationEvent(CustomEvent event) {
        sendQQMessage(event.getUserName());
    }

    public void sendQQMessage(String message) {
        // todo 给QQ发送消息
        log.info("给QQ发送:{}消息", message);
    }

}

测试发送消息的代码

我们使用 Spring 的事件发布者 ApplicationEventPublisher 来发布自定义的CustomEvent事件。

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
* @author : zanglikun
* @date : 2024/6/16 上午11:52
* @desc : Copyright © zanglikun.com
*/
@Api(tags = "事件测试")
@RestController
@RequestMapping("/event/api/v1/")
public class EventController {


// 注入一个事件发布对象,用来发布事件
@Resource
private ApplicationEventPublisher eventPublisher;

@GetMapping
@ApiOperation("发送")
public String sendMessage(String msg) {
if (StringUtils.isBlank(msg)) {
msg = "前端没有输入param msg!";
}

// 构造事件对象
CustomEvent customEvent = new CustomEvent(this);
customEvent.setUserName(msg);
// 发送事件
eventPublisher.publishEvent(customEvent);
return "发送成功";
}
}


这个例子展示了 Spring 事件在真实业务中的使用。通过使用事件机制,我们可以将不同部分的逻辑解耦。

SpringEvent 事务相关

在 Spring 中,事件的发布和监听通常是在同一个事务内执行的。这意味着如果事件发布的过程中发生了事务回滚,那么对应的事件监听器中的逻辑也会被回滚。

我一开始想的是:如果A服务发送了一个事件,然后A服务的监听器里出现了异常。这样就会导致数据不一致的事务问题。这是一件很麻烦的事情。但是实际情况监听器与发送的线程一般来说是同一个,就不会有数据没回滚的问题了。如果是集群,更是如此了!

Spring 事件的应用场景包括但不限于

  1. 异步处理任务: 当某些任务不需要立即执行,而是可以延迟执行时,可以使用 Spring 事件来触发异步处理任务,从而提高系统的响应速度和并发能力。
  2. 业务流程触发: 在复杂的业务流程中,不同步骤之间可能需要进行通信和协调。通过使用 Spring 事件,可以在不同步骤之间进行通信,触发后续的业务逻辑。
  3. 领域事件驱动开发(Domain-Driven Design,DDD): 在领域驱动设计中,领域事件是一种描述领域中发生的事情的方式。通过使用 Spring 事件,可以将领域事件与业务逻辑解耦,从而更好地实现领域驱动设计。
  4. 系统集成: 在大型系统中,不同模块之间可能需要进行通信和协作。通过使用 Spring 事件,可以实现系统内部模块之间的解耦和通信。
  5. 日志记录和监控: 在系统中触发某些关键事件时,可以使用 Spring 事件来记录日志或进行监控,以便及时发现和解决问题。

总之,Spring 事件适用于需要实现模块之间解耦、异步处理任务、业务流程触发、领域事件驱动设计以及系统集成等场景。通过使用 Spring 事件,可以更好地组织和管理系统中的各个部分,提高系统的可维护性、可扩展性和可测试性。

关于解耦:采用的方式是:@Async

特殊说明:
上述文章均是作者实际操作后产出。烦请各位,请勿直接盗用!转载记得标注原文链接:www.zanglikun.com
第三方平台不会及时更新本文最新内容。如果发现本文资料不全,可访问本人的Java博客搜索:标题关键字。以获取全部资料 ❤