• SpringBoot项目实现发布订阅模式,真的很简单


    大家好,我是老三,在项目里,经常会有一些主线业务之外的其它业务,比如,下单之后,发送通知、监控埋点、记录日志……

    这些非核心业务,如果全部一梭子写下去,有两个问题,一个是业务耦合,一个是串行耗时。

    ​下单之后的逻辑

    所以,一般在开发的时候,都会把这些操作å抽象成观察者模式,也就是发布/订阅模式(这里就不讨论观察者模式和发布/订阅模式的不同),而且一般会采用多线程的方式来异步执行这些观察者方法。

    ​观察者模式

    一开始,我们都是自己去写观察者模式。

    自己实现观察者模式

    观察者简图

    观察者

    • 观察者定义接口

    1. /**
    2. * @Author: fighter3
    3. * @Description: 观察者接口
    4. * @Date: 2022/11/7 11:40 下午
    5. */
    6. public interface OrderObserver {
    7. void afterPlaceOrder(PlaceOrderMessage placeOrderMessage);
    8. }
    • 具体观察者@Slf4j
      public class OrderMetricsObserver implements OrderObserver {
      @Override
      public void afterPlaceOrder(PlaceOrderMessage placeOrderMessage) {
      log.info("[afterPlaceOrder] metrics");
      }}@Slf4j
      public class OrderLogObserver implements OrderObserver{
      @Override
      public void afterPlaceOrder(PlaceOrderMessage placeOrderMessage) {
      log.info("[afterPlaceOrder] log.");
      }}@Slf4j
      public class OrderNotifyObserver implements OrderObserver{
      @Override
      public void afterPlaceOrder(PlaceOrderMessage placeOrderMessage) {
      log.info("[afterPlaceOrder] notify.");
      }}
      • 业务通知观察者
      • 日志记录观察者
      • 监控埋点观察者

    被观察者

    • 消息实体定义
    1. @Data
    2. public class PlaceOrderMessage implements Serializable {
    3. /**
    4. * 订单号
    5. */
    6. private String orderId;
    7. /**
    8. * 订单状态
    9. */
    10. private Integer orderStatus;
    11. /**
    12. * 下单用户ID
    13. */
    14. private String userId;
    15. //……
    16. }
    • 被观察者抽象类
    1. public abstract class OrderSubject {
    2. //定义一个观察者列表
    3. private List<OrderObserver> orderObserverList = new ArrayList<>();
    4. //定义一个线程池,这里参数随便写的
    5. ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(6, 12, 6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(30));
    6. //增加一个观察者
    7. public void addObserver(OrderObserver o) {
    8. this.orderObserverList.add(o);
    9. }
    10. //删除一个观察者
    11. public void delObserver(OrderObserver o) {
    12. this.orderObserverList.remove(o);
    13. }
    14. //通知所有观察者
    15. public void notifyObservers(PlaceOrderMessage placeOrderMessage) {
    16. for (OrderObserver orderObserver : orderObserverList) {
    17. //利用多线程异步执行
    18. threadPoolExecutor.execute(() -> {
    19. orderObserver.afterPlaceOrder(placeOrderMessage);
    20. });
    21. }
    22. }
    23. }

    这里利用了多线程,来异步执行观察者。

    • 被观察者实现类
    1. /**
    2. * @Author: fighter3
    3. * @Description: 订单实现类-被观察者实现类
    4. * @Date: 2022/11/7 11:52 下午
    5. */
    6. @Service
    7. @Slf4j
    8. public class OrderServiceImpl extends OrderSubject implements OrderService {
    9. /**
    10. * 下单
    11. */
    12. @Override
    13. public PlaceOrderResVO placeOrder(PlaceOrderReqVO reqVO) {
  • 相关阅读:
    selenium +IntelliJ+firefox/chrome 环境全套搭配
    vue3.2+ts封装axios
    猿创征文|Spring Boot 整合分布式调度框架:xxl-job
    2022年数维杯国际大学生数学建模挑战赛C题如何利用大脑结构特征和认知行为特征诊断阿尔茨海默病解题过程
    【Kubernetes 系列】K8S 进阶 万字讲述 Windows HostProcess 运行容器化负载
    【Python机器学习】零基础掌握GaussianProcessRegressor高斯过程
    亚马逊短视频制作需要注意什么?
    IB各科目组哪些课程评估/考试人数最多?
    【Python音视频技术】用moviepy实现图文成片功能
    【零基础入门MyBatis系列】第三篇——使用MyBatis完成CRUD
  • 原文地址:https://blog.csdn.net/Java_zhujia/article/details/128181726