搜索
您的当前位置:首页正文

业务解耦神器 Spring Event

来源:独旅网

概述

在实际的业务开发中,我们经常使用MQ来进行业务的解耦合,比如电商场景下,下单是一个主流程,下单完成后发出下单成功的MQ,优惠券、京豆等业务系统对MQ进行消费,这样能够将下单核心流程与非核心流程进行业务解耦。

但除了跨应用的分布式系统需要使用MQ进行解耦之外,单一应用在某些业务场景下,对业务进行解耦也是一种常见的场景。

Spring Event作为Spring框架的一部分,为开发者提供了一种轻量级的事件驱动机制,能够有效地实现应用内的业务解耦。本文将深入探讨Spring Event的优势、实现方法及其在实际项目中的应用。

Spring Event 介绍

发布-订阅模式(Publish-Subscribe Pattern)是一种消息传递模式,在Java中通常用于实现松耦合的系统架构。在这种模式中,消息的发送者(发布者)和消息的接收者(订阅者)之间没有直接的联系,而是通过一个消息代理(通常称为事件总线或消息中间件)来进行通信。在Spring Boot中,发布-订阅模式通常是通过Spring的事件机制来实现的,允许组件之间进行松耦合的通信,即Spring Event。它主要包括以下几个核心部分:事件(Event)、事件发布者(Event Publisher)和事件监听器(Event Listener)。

基本概念

实现步骤

这里以导航场景举例进行实现步骤的举例,当发生交通事故时,地图上需要显示交通事故图标以提醒用户,也需要发送通知给其他用户提醒其小心驾驶。

1. 定义事件类

首先,定义一个事件类,继承自ApplicationEvent。这个类用于封装要传递的信息。

  
import org.springframework.context.ApplicationEvent;  
  
public class TrafficEvent extends ApplicationEvent {  
/**  
 * source the object on which the event initially occurred or with  
 *               which the event is associated 
 */
	private String message;  
    public TrafficEvent(Object source,String message) {  
        super(source);  
        this.message = message;  
    }  
  
    public String getMessage() {  
        return message;  
    }  
}

2. 创建事件发布者

创建一个Spring组件,用于发布事件。可以通过ApplicationEventPublisher来发布事件。

import lombok.RequiredArgsConstructor;  
import lombok.extern.slf4j.Slf4j;  
import org.springframework.context.ApplicationEventPublisher;  
import org.springframework.stereotype.Component;  
@RequiredArgsConstructor  
@Slf4j  
@Component  
public class TrafficPublish {  
  
    private final ApplicationEventPublisher publisher;  
  
    public void publish(String message){  
        TrafficEvent trafficEvent = new TrafficEvent(this,message);  
        publisher.publishEvent(trafficEvent);  
    }  
}

3. 创建事件监听器

创建一个事件监听器,使用@EventListener注解来监听事件,也可以通过实现ApplicationListener接口来进行监听。

  • 使用@EventListener注解
import lombok.extern.slf4j.Slf4j;  
import org.springframework.context.event.EventListener;  
import org.springframework.stereotype.Component;  
  
@Slf4j  
@Component  
public class MapRenderListener  {  
  
    @EventListener  
    public void onApplicationEvent1(TrafficEvent trafficEvent){  
        log.info("小程序地图渲染程序收到一条消息:source:{},time:{}",trafficEvent.getSource(),trafficEvent.getTimestamp());  
        log.info("消息内容:{}",trafficEvent.getMessage());  
    }  
  
    @EventListener  
    public void onApplicationEvent2(TrafficEvent trafficEvent){  
        log.info("App地图渲染程序收到一条消息:source:{},time:{}",trafficEvent.getSource(),trafficEvent.getTimestamp());  
        log.info("消息内容:{}",trafficEvent.getMessage());  
    }  
  
}
  • 实现ApplicationListener接口
import lombok.extern.slf4j.Slf4j;  
import org.springframework.context.ApplicationListener;  
import org.springframework.stereotype.Component;  
@Slf4j  
@Component  
public class NoticeTrafficListener implements ApplicationListener<TrafficEvent> {  
    @Override  
    public void onApplicationEvent(TrafficEvent trafficEvent) {  
        log.info("导航应用收到一条消息:source:{},time:{}",trafficEvent.getSource(),trafficEvent.getTimestamp());  
        log.info("消息内容:{}",trafficEvent.getMessage());  
    }  
}

4. 使用发布-订阅模式

在Spring Boot应用中使用发布者来发布事件,然后监听器会自动接收到事件。这里我们使用一个Controller 通过接收请求来发布事件。

@Controller  
@CrossOrigin  
public class ControllerTest {  
    @Autowired  
    private TrafficPublish trafficPublish;  
  
    @RequestMapping("/publish")  
    @ResponseBody  
    public String publish(String message){  
        trafficPublish.publish(message);  
        return "publish";  
    }
}
日志打印图示

通过上面的四个步骤,日志打印(这里的日志打印使用了笔者自己封装的组件,可在方法执行前后对出入参及耗时进行打印)如下图所示:

Spring Event 扩展

publishEvent方法是阻塞的

通过打印的日志我们也可以看到ApplicationEventPublisher.publishEvent方法是阻塞的,当ApplicationEventPublisher.publishEvent方法发布一个事件后,会同步调用所有的事件监听者任务执行逻辑,事件的发布和所有监听者的任务调用都是在一个线程里面,为了防止发布消息的阻塞或者监听消息处理的阻塞,可以在监听消息内,使用独立的线程池进行执行。

Spring Event 内置事件

Spring Framework 提供了一些内置事件,用于帮助开发者在应用程序上下文中处理常见的生命周期事件。这些内置事件包括:

  1. ContextRefreshedEvent:当应用程序上下文初始化或刷新时发布该事件。这可以用于在应用程序完全启动后执行某些逻辑。

  2. ContextStartedEvent:当应用程序上下文启动时发布该事件。通常用于在上下文启动后执行某些操作。

  3. ContextStoppedEvent:当应用程序上下文停止时发布该事件。可以用于在应用程序停止时执行清理工作。

  4. ContextClosedEvent:当应用程序上下文关闭时发布该事件。适合用于释放资源或执行关闭前的清理操作。

  5. RequestHandledEvent(在 Spring MVC 中):当一个 HTTP 请求被处理后发布该事件。适合用于监控和统计请求处理情况。

ApplicationEvent中的source

继承 ApplicationEvent后要重新父类的构造方法,并且source字段不能为空,否则会抛出异常,并且source字段只能在构造函数中进行传递。

监听所有类型事件(没什么用)

监听器可以针对自己感兴趣的事件类型进行监听,如示例代码中的TrafficEvent,如果想监听所有类型的事件,则可监听ApplicationEvent

因篇幅问题不能全部显示,请点此查看更多更全内容

热门图文

Top