SpringBoot中使用SpringEvent业务解耦神器实现监听发布事件同步异步执行任务

场景

SpringBoot中使用单例模式+ScheduledExecutorService实现异步多线程任务(若依源码学习):

SpringBoot中使用单例模式+ScheduledExecutorService实现异步多线程任务(若依源码学习)-CSDN博客

设计模式-观察者模式在Java中的使用示例-环境监测系统:

设计模式-观察者模式在Java中的使用示例-环境监测系统_java observer使用-CSDN博客

开发过程中,业务逻辑可能非常复杂,核心业务 + N个子业务。

如果都放到一块儿去做,代码可能会很长,耦合度不断攀升。

还有一些业务场景不需要在一次请求中同步完成,比如邮件发送、短信发送等。

MQ 可以解决这个问题,但 MQ 重,非必要不提升架构复杂度。

针对这些问题,我们了解一下 Spring Event。

Spring Event(Application Event)其实就是一个观察者设计模式,

一个 Bean 处理完成任务后希望通知其它 Bean 或者说一个 Bean 想观察监听另一个Bean 的行为。

注:

博客:
霸道流氓气质-CSDN博客

实现

1、以下订单时同步校验订单价格和异步发送邮件通知为例

通过使用时间发布订阅的形式进行解耦。

同步校验订单价格实现

首先自定义事件,该事件携带订单id

public class OrderProductEvent {

    private String orderId;

    public OrderProductEvent(String orderId){
        this.orderId = orderId;
    }

    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }
}

2、定义监听器

使用@EventListener注解监听并处理事件

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

@Component
public class OrderProductListener {

    @EventListener(OrderProductEvent.class)
    public void checkPrice(OrderProductEvent event){
        String orderId = event.getOrderId();
        System.out.println("校验订单价格开始:"+ LocalDateTime.now());
        try {
            TimeUnit.SECONDS.sleep(2);
            System.out.println("校验订单:"+orderId+"价格完成"+LocalDateTime.now());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

3、定义发布者

通过applicationEventPublisher.publishEvent发布事件

首先新建订单Service接口

public interface OrderService {
    String buyOrder(String orderId);
}

接口实现

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

@Service
public class OrderServiceImpl implements OrderService{

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Override
    public String buyOrder(String orderId) {
        //其它业务省略
        //校验订单价格-同步进行
        applicationEventPublisher.publishEvent(new OrderProductEvent(orderId));
        return "下单成功";
    }
}

4、编写单元测试

import lombok.SneakyThrows;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = RuoYiApplication.class,webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SpringEventTest {

    @Autowired
    private OrderService orderService;

    @Test
    @SneakyThrows
    public void getDictLable() {
        System.out.println("下订单开始:"+ LocalDateTime.now());
        String s = orderService.buyOrder("0001");
        System.out.println(s);
        //执行其他业务
        TimeUnit.SECONDS.sleep(5);
        System.out.println("下订单结束:"+ LocalDateTime.now());
    }
}

5、单元测试运行结果

6、Spring Event 异步实现

有些业务场景不需要在一次请求中同步完成,比如邮件发送、短信发送等。

自定义发送邮件事件

import lombok.AllArgsConstructor;

@AllArgsConstructor
public class MsgEvent {
    public String orderId;

    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }
}

7、定义监听器

import lombok.SneakyThrows;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

@Component
public class MsgListener {

    @Async
    @SneakyThrows
    @EventListener(MsgEvent.class)
    public void sendMsg(MsgEvent event){
        String orderId = event.getOrderId();
        System.out.println("订单"+orderId+"开始发送邮件"+ LocalDateTime.now());
        TimeUnit.SECONDS.sleep(2);
        System.out.println("订单"+orderId+"发送邮件完成"+ LocalDateTime.now());
    }
}

需要添加@Async注解

并且需要在启动类上添加@EnableAsync注解

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
@EnableAsync
public class RuoYiApplication
{
    public static void main(String[] args)
    {
        SpringApplication.run(RuoYiApplication.class, args);
}

8、同样在上面发布者中添加发布事件

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

@Service
public class OrderServiceImpl implements OrderService{

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Override
    public String buyOrder(String orderId) {
        //其它业务省略
        //校验订单价格-同步进行
        applicationEventPublisher.publishEvent(new OrderProductEvent(orderId));
        //发送邮件-异步进行
        applicationEventPublisher.publishEvent(new MsgEvent(orderId));
        return "下单成功";
    }
}

9、单元测试同上,运行结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/311608.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

win7添加access的odbc数据源

从控制面板打开odbc数据源;如果像下面没有access的驱动程序, 根据资料,打开C盘-Windows-SysWow64-odbcad32.exe,看一下就有了; 然后添加用户DSN,选中access的驱动程序, 自己输入一个数据源名&am…

北斗卫星助力智慧公园实现智能化管理

北斗卫星助力智慧公园实现智能化管理 智慧公园是以信息技术为核心,以人工智能为驱动,运用物联网技术对公园进行智能化管理和服务的创新模式。而北斗卫星系统的应用,为智慧公园提供了更强大的支持和保障。下面我们来详细了解一下北斗卫星在智…

【c++】list迭代器失效问题

目录 一、list iterator的使用 二、list的迭代器失效 一、list iterator的使用 对于list的迭代器的用法,可以将它看做一个指针(实际要更加复杂)来使用,该指针指向list中的一个节点。 【注意】 (1)begin和end为正向迭代器&#x…

MobaXterm游戏讲解

前言 没想到吧,这里还有游戏,以下是玩法 玩法 注 点击Type可以自由更改地图大小 1.Netwalk 这个游戏是用鼠标点击每一个格子,进行旋转方向,使得所有方块连接接来,全部变成亮蓝色 2.Mines 这个就是扫雷了&#xff…

Python学习从0到1 day1 你好 Python

我会在那腥臭腐朽的日子里熠熠生辉 ——24.1.11 1.第一个Python程序 安装python程序,输出第一个程序:你好,世界 print("Hello World"); 2.Python解释器 python解释器,是一个计算机程序,用来翻译python代码,并提交给计算机执行 功能:1.翻译代码 2.提交给计算机…

ssm+vue的城投公司企业人事管理系统设计与实现(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频: ssmvue的城投公司企业人事管理系统设计与实现(有报告)。Javaee项目,ssm vue前后端分离项目。 项目介绍: 采用M(model)V(view)C(controller&#x…

从聚水潭到金蝶云星空通过接口配置打通数据

从聚水潭到金蝶云星空通过接口配置打通数据 对接系统:聚水潭 聚水潭SaaSERP于2014年4月上线,目前累计超过2.5万商家注册使用,成为淘宝应用服务市场ERP类目商家数和商家月订单增速最快的ERP。2014年及2015年“双十一”当天,聚水潭S…

如何利用ChatGPT快速生成月报?

随着每个月的结束,个人和团队经常需要编写月报来回顾和总结。这项任务通常消耗大量时间和精力。幸运的是,借助ChatGPT,这个过程可以变得更加简单和高效。接下来,我将详细介绍如何利用ChatGPT快速生成月报,从而帮助你节…

一个完整的流程表单流转

1.写在前面 一个完整的流程表单审批(起表单-->各环节审批-->回退-->重新审批-->完成),前端由Vue2jsElement UI升级为Vue3tsElement Plus,后端流程框架使用Flowable,项目参考了ruoyi-vue-pro(https://gite…

程序员有哪些接单的渠道?

这题我会!程序员接单的渠道那可太多了,想要接到合适的单子,筛选一个合适的平台很重要。如果你也在寻找一个合适的接单渠道,可以参考以下这些方向。 首先,程序员要对接单有一个基本的概念:接单渠道可以先粗略…

pandas笔记:找出在一个dataframe但不在另一个中的index

1 问题描述 假设我们有两个dataframe(这一段代码)来自transbigdata 笔记:官方文档案例1(出租车GPS数据处理)-CSDN博客 data tbd.clean_outofshape(data, sz, col[Lng, Lat], accuracy500) data data2 tbd.clean_ta…

科研学习|论文解读——信息世界映射方法

题目:信息世界映射的下一步是什么?在情境中理解信息行为/实践的国际化和多学科方法(What is next for information world mapping? International and multidisciplinary approaches to understanding information behaviors/ practices in …

6.2 声音编辑工具GoldWave5简介(2)

6.2.2转换声音格式 GoldWave5支持多种声音格式,它不但可以编辑扩展名是wav、mp3、au、voc等格式的声音文件,还可以编辑Apple电脑所使用的声音文件;并且GoldWave5还可以把Matlab中的mat文件当作声音文件来处理。利用这些功能可以很容易进行声…

深度学习笔记(三)——NN网络基础概念(神经元模型,梯度下降,反向传播,张量处理)

文中程序以Tensorflow-2.6.0为例 部分概念包含笔者个人理解,如有遗漏或错误,欢迎评论或私信指正。 截图部分引用自北京大学机器学习公开课 人工智能算法的主流分类 首先明白一个概念,广义上的人工智能算法并不是只有Machine Learning或Deep …

Maven和MyBatis框架简单实现数据库交互

MyBatis是一种基于Java语言的持久层框架,它的主要目的是简化与数据库的交互过程。MyBatis通过XML或注解配置来映射Java对象和数据库表之间的关系,并提供了灵活的查询方式和结果集处理机制。MyBatis还提供了事务管理、缓存机制、插件扩展等特性。 使用My…

关于httpClient 使用的注意事项

关于httpClient 使用的注意事项 用例 PoolingHttpClientConnectionManager connectionManager new PoolingHttpClientConnectionManager();// 最大连接数-不设置默认20connectionManager.setMaxTotal(200);// 每个路由最大连接数-不设置默认2connectionManager.setDefaultMax…

深度解析Java中的ReadWriteLock:高效处理并发读写操作

第1章:引言 大家好,我是小黑,今天咱们聊聊读写锁。当多个线程同时对同一数据进行读写操作时,如果没有合理的管理,那数据就乱套了。就好比小黑在写日记,突然来了一帮朋友,大家都想往日记本上写点…

linux 网络基础配置

将Linux主机接入到网络,需要配置网络相关设置一般包括如下内容: 主机名 iP/netmask (ip地址,网关) 路由:默认网关 网络连接状态 DNS服务器 (主DNS服务器 次DNS服务器 第三个DNS服务器) 一、…

工作每天都在用的 DNS 协议,你真的了解么?

我们经常访问一些网址的时候,浏览器里输入类似于 www.baidu.com 这样的地址,那么在浏览器里输入这个地址---> 百度服务器给我们返回这个百度的页面,中间的过程是什么样的呢? 带着这个问题,我们一起来解析一下其中的…

java通过HttpClient方式实现https请求的工具类(绕过证书验证)

目录 一、引入依赖包二、HttpClient方式实现的https请求工具类三、测试类 一、引入依赖包 引入相关依赖包 <!--lombok用于简化实体类开发--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><option…