前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >代码耦合度那么高,试试Spring Event!

代码耦合度那么高,试试Spring Event!

作者头像
小四的技术之旅
发布2022-07-26 08:00:46
1K1
发布2022-07-26 08:00:46
举报

码农在囧途

在时光这条隧道上,我们还是少走一点回头路,少去留恋一点过往,还是得保持前进,我们会被拒绝,会被嘲笑,会被蔑视,甚至被唾骂,不过这都不是你应该去关心的事,不要被其羁绊,相反,得将其作为助推器,作为生命的燃料,再也没有这样的事更能激起一个人斗志,虽然结果看来事如此的渺茫,不过,依然相信曙光!

前言

今天来分享一下Spring Event,那么在说Spring Event之前,我们得先清楚为什么要用Spring Event,使用它能够带来什么好处,它适合什么样的场景?

首先为什么要使用Spring Event?

我们都知道,代码耦合度不能太高,所以我们要尽量的将代码解耦,提到解耦,我们会想到使用消息队列来解耦,消息生产者发布消息,消息消费者消费消息,这样,两个端就解耦了,消费者只需要订阅生产者,然后生产者推动消息到消费者,不过使用消息队列的话成本比较大。

我们也可以使用观察者模式来进行解耦,观察者模式就是发布订阅模式,Spring Event就是观察者模式,只是我们如果直接去写观察者模式,那么需要考虑很多东西,所以使用Spring Event便是一个不错的选择。

综上,Spring Event能够降低我们代码的耦合度,使我们的系统具有更高的可扩展性,但是它也有局限性,如果我们的系统很庞大,复杂,分布式的情况下,那么Spring Event可能就不怎么适合了,那么我们肯定会选择消息队列。

Spring Event实现下单流程

下单后,我们需要保存订单,然后进行扣减库存,扣减账户余额,短信通知等操作,我们此处使用Spring Event来实现这些操作的解耦,不过只适合单体架构,如果项目是微服务,分布式,那么使用Spring Event自然就不行,因为扣减库存,扣减账户余额,短信通知这几个接口都会是单独的服务。

项目结构

代码语言:javascript
复制
└─com
    └─steakliu
        └─event
            │  EventApplication.java
            │  
            ├─order
            │  ├─controller
            │  │      OrderController.java
            │  │      
            │  ├─dto
            │  │      MessageDTO.java
            │  │      OrderDTO.java
            │  │      StockDTO.java
            │  │      UserDTO.java
            │  │      
            │  ├─event
            │  │      MessageEvent.java
            │  │      StockEvent.java
            │  │      UserEvent.java
            │  │      
            │  ├─listener
            │  │      MessageListener.java
            │  │      StockListener.java
            │  │      UserListener.java
            │  │      
            │  └─service
            │          OrderService.java

定义Event(事件)

这里的事件里面就包含这个事件需要传递的信息,因为我们下面使用的是注解的方式,所以此处就比较简单,就是普通的实体定义,如果我们不使用注解,那么此处需要继承ApplicationEvent,不然事件无法进行传递,我们以最简洁的方式来进行。

库存事件

代码语言:javascript
复制
/**
 * 功能说明:库存事件
 *
 * <p>
 * Original @Author: steakliu-刘牌, 2022-06-25  19:25
 * <p>
 * Copyright (C)2020-2022  小四的技术之旅 All rights reserved.
 */
@Data
@AllArgsConstructor
public class StockEvent {
    //库存DTO
    private StockDTO stockDTO;
}

账户事件

代码语言:javascript
复制
/**
 * 功能说明:账户事件
 *
 * <p>
 * Original @Author: steakliu-刘牌, 2022-06-25  19:35
 * <p>
 * Copyright (C)2020-2022  小四的技术之旅 All rights reserved.
 */
@Data
@AllArgsConstructor
public class UserEvent {
    private UserDTO userDTO;
}

消息事件

代码语言:javascript
复制
/**
 * 功能说明:消息事件
 *
 * <p>
 * Original @Author: steakliu-刘牌, 2022-06-25  19:51
 * <p>
 * Copyright (C)2020-2022  小四的技术之旅 All rights reserved.
 */
@Data
@AllArgsConstructor
public class MessageEvent {
    private MessageDTO messageDTO;
}

定义监听器

我们定义监听器后,并监听对应事件,当对应的事件被发布后,就会触发监听器,监听器就可以进行业务操作,我们下面使用注解@EventListener的形式来定义监听器,也可以实现ApplicationListener接口,不过推荐使用@EventListener,下面我们也使用了@Async注解,因为这些操作应该都是异步的,使用@Async,需要在SpringBoot的启动类上加上@EnableAsync注解。

库存监听器

代码语言:javascript
复制
/**
 * 功能说明:库存监听器
 *
 * <p>
 * Original @Author: steakliu-刘牌, 2022-06-25  19:27
 * <p>
 * Copyright (C)2020-2022  小四的技术之旅 All rights reserved.
 */
@Component
@Slf4j
public class StockListener {

    @Async
    @EventListener(StockEvent.class)
    public void decreaseStock(StockEvent stockEvent) throws InterruptedException {
        Thread.sleep(2000);
        log.info("扣减id为【{}】的商品库存,扣减数量为【{}】",stockEvent.getStockDTO().getCommodityId(),stockEvent.getStockDTO().getNum());
    }
}

账户监听器

代码语言:javascript
复制
/**
 * 功能说明:账户监听器
 *
 * <p>
 * Original @Author: steakliu-刘牌, 2022-06-25  19:35
 * <p>
 * Copyright (C)2020-2022  小四的技术之旅 All rights reserved.
 */
@Component
@Slf4j
public class UserListener {

    @Async
    @EventListener(UserEvent.class)
    public void decreaseBalance(UserEvent userEvent) throws InterruptedException {
        log.info("扣减账户【{}】余额,扣减金额为:【{}】",userEvent.getUserDTO().getUserId(),userEvent.getUserDTO().getMoney());
    }
}

消息监听器

代码语言:javascript
复制
/**
 * 功能说明:消息监听器
 *
 * <p>
 * Original @Author: steakliu-刘牌, 2022-06-25  19:52
 * <p>
 * Copyright (C)2020-2022  小四的技术之旅 All rights reserved.
 */
@Component
@Slf4j
public class MessageListener {

    @Async
    @EventListener(MessageEvent.class)
    public void sendMsg(MessageEvent messageEvent){
        log.info("发送短信至【{}】",messageEvent.getMessageDTO().getTel());
    }
}

发布事件

当我们进行下单的时候,使用ApplicationEventPublisher发布事件,对应的事件将会被发布,那么被监听对应事件的监听器将会被触发。

代码语言:javascript
复制
/**
 * 功能说明:订单Service
 *
 * <p>
 * Original @Author: steakliu-刘牌, 2022-06-25  19:52
 * <p>
 * Copyright (C)2020-2022  小四的技术之旅 All rights reserved.
 */
@Component
@Slf4j
@AllArgsConstructor
public class OrderService {

    private ApplicationEventPublisher applicationEventPublisher;

    public void placeOrder(OrderDTO orderDTO){
        log.info("=======开始下单操作=======");
        //保存订单
        this.saveOrder(orderDTO);

        //扣减库存
        StockDTO stockDTO = new StockDTO().setCommodityId(orderDTO.getCommodityId()).setNum(orderDTO.getNum());
        applicationEventPublisher.publishEvent(new StockEvent(stockDTO));

        //扣减余额
        UserDTO userDTO = new UserDTO().setUserId(orderDTO.getUserId()).setMoney(orderDTO.getPrice().multiply(new BigDecimal(orderDTO.getNum())));
        applicationEventPublisher.publishEvent(new UserEvent(userDTO));

        //短信通知
        MessageDTO messageDTO = new MessageDTO().setTel(orderDTO.getTel());
        applicationEventPublisher.publishEvent(new MessageEvent(messageDTO));

    }

    private void saveOrder(OrderDTO orderDTO){
        log.info("保存订单:【{}】",orderDTO);
    }
}

下单Controller

代码语言:javascript
复制
/**
 * 功能说明:下单
 *
 * <p>
 * Original @Author: steakliu-刘牌, 2022-06-25  20:00
 * <p>
 * Copyright (C)2020-2022  小四的技术之旅 All rights reserved.
 */
@RestController
@RequestMapping("/order")
@AllArgsConstructor
public class OrderController {

    final OrderService orderService;

    @PostMapping("/placeOrder")
    public String placeOrder(@RequestBody OrderDTO orderDTO){
        orderService.placeOrder(orderDTO);
        return "下单成功";
    }
}

输出

从输出可以看出三个操作是异步的,在库存监听器哪里休眠了2s,发送短信和扣减余额接口并没有被阻塞,因为使用了@Async注解。

总结

从上面的解说和实战我们看出使用Spring Event还是比较简单的,对于解耦我们的代码是有很大的作用的,所以我们在工作中如果如果遇到代码耦合度过于高的时候,可以考虑使用Spring Event。

今天的分享就到这里,感谢你的观看,我们下期见。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-06-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 刘牌 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 码农在囧途
  • 前言
  • Spring Event实现下单流程
  • 项目结构
  • 定义Event(事件)
    • 库存事件
      • 账户事件
        • 消息事件
        • 定义监听器
          • 库存监听器
            • 账户监听器
              • 消息监听器
              • 发布事件
              • 下单Controller
                • 输出
                • 总结
                相关产品与服务
                消息队列 CMQ 版
                消息队列 CMQ 版(TDMQ for CMQ,简称 TDMQ CMQ 版)是一款分布式高可用的消息队列服务,它能够提供可靠的,基于消息的异步通信机制,能够将分布式部署的不同应用(或同一应用的不同组件)中的信息传递,存储在可靠有效的 CMQ 队列中,防止消息丢失。TDMQ CMQ 版支持多进程同时读写,收发互不干扰,无需各应用或组件始终处于运行状态。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档