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

发布时间:2024年01月11日

场景

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

文章来源:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/135527434
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。