首页 > 其他分享 >SpringBoot中使用SpringEvent业务解耦神器实现监听发布事件同步异步执行任务

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

时间:2024-01-11 14:15:09浏览次数:41  
标签:orderId 异步 String springframework SpringEvent org import public SpringBoot

场景

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

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/135504554

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

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/133772928

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

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

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

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

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

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

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

注:

博客:
https://blog.csdn.net/badao_liumang_qizhi

实现

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、单元测试同上,运行结果

 

标签:orderId,异步,String,springframework,SpringEvent,org,import,public,SpringBoot
From: https://www.cnblogs.com/badaoliumangqizhi/p/17958460

相关文章

  • springBoot自定义拦截器
    编写FuelH5InterceptorConfig配置类packagecom.fuel.framework.config;importcom.fuel.framework.interceptor.FuelH5Interceptor;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Configuration;importorg......
  • SpringBoot3.x升级整合各依赖
    开发环境开发依赖版本openJDK17SpringBoot3.2.1以下是SpringBoot3.x版本依赖坐标发生变化的常用框架一、整合MybatisPlusSpringBoot2.x版本引入的依赖是:<mybatis.plus.version>3.4.2</mybatis.plus.version><dependency><groupId>com.baomidou</gro......
  • Springboot 项目集成 PageOffice V6 最简单代码
    本文描述了PageOffice产品在Springboot项目中如何集成调用。(本示例使用了Thymeleaf模板引擎)新建Springboot项目:pageoffice6-springboot2-simple在您项目的pom.xml中通过下面的代码引入PageOffice依赖。pageoffice.jar已发布到Maven中央仓库(opensnewwindow),建议使用最新......
  • SpringBoot配置加载优先级
    优先级:命令行参数>环境变量>配置文件1.命令行参数配置java-jar-Dserver.port=8000ruoyi-admin.jar2.环境变量配置linux系统环境:#申明环境变量exportSERVER_PORT=10000#执行jar包java-jardemo.jarwindow系统环境:idea中:java-jar命令使用环境变量需要再win系统环境变量中......
  • SpringBoot-Mybatis整合
     创建数据库CREATETABLE`user`( `id`int(11)NOTNULLAUTO_INCREMENTcomment'学号', `name`varchar(20)DEFAULTNULL, `pwd`int(11)DEFAULTNULL, PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=18DEFAULTCHARSET=utf8;创建一个springboo......
  • Springboot 扩展点
    1.ApplicationContextInitializerorg.springframework.context.ApplicationContextInitializer这是整个spring容器在刷新之前初始化ConfigurableApplicationContext的回调接口,简单来说,就是在容器刷新之前调用此类的initialize方法。这个点允许被用户自己扩展。用户可以在......
  • SpringBoot中使用单例模式+ScheduledExecutorService实现异步多线程任务(若依源码学习
    场景若依前后端分离版手把手教你本地搭建环境并运行项目:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108465662设计模式-单例模式-饿汉式单例模式、懒汉式单例模式、静态内部类在Java中的使用示例:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/......
  • springboot学习日记(八)
    前后端分离的项目static目录下一般不存放东西。static目录下的图片等资源默认做了映射,直接在localhost:8080下访问即可。表单中的enctype属性决定了服务器对表单数据的编码,将该属性设置成form-data时可以通过filename找到路径,用content-type设置内容格式来上传文件。可使用Multi......
  • SpringBoot WebSocket 样例
    SpringBootWebSocket样例pom.xml依赖配置<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><dependency><groupId>javax.webso......
  • 8、SpringBoot2之打包及运行
    为了演示高级启动时动态配置参数的使用,本文在SpringBoot2之配置文件的基础上进行8.1、概述普通的web项目,会被打成一个war包,然后再将war包放到tomcat的webapps目录中;当tomcat启动时,在webapps目录中的war包会自动解压,此时便可访问该web项目的资源或服务;因为......