解耦神器Event和EventListener

总结版

说到解耦,就不得不说经典的订阅和发布者模式,我们当然可以在代码中自己实现一套这样的模式,不过spring中已经帮忙我们实现好了现成的,直接拿来用即可。

即发布事件时用

scss 复制代码
ApplicationContextHelper.getApplicationContext().publishEvent(Event event)

监听时用

typescript 复制代码
@EventListener
public void onEvent(Event event){
//自己的业务逻辑,相关参数可以放在event中
}

另外,在spring4.2+中,还额外提供 @TransactionalEventListener注解,进行升级,可以在event的各个事务阶段进行监听。

问题

许多的系统都会涉及到订单,在基金系统中也不例外。一开始订单提交完成之后,动作很简单,打印订单就可以了,不过随着功能越来越多,后面的动作也越来越多,加入了发送通知邮件,冻结,解冻,生成订单文件等等,

这个类里面的placeOrder的方法也越来越长,不加约束时轻易超过上千行,可读性极差,也极难再做扩展。

csharp 复制代码
public void placeOrder(){
   //...上千行内容,所有逻辑全写在一起
}

后面抽象出来一部分动作,但是内容也时常变动

scss 复制代码
public void placeOrder(){
    //...正常订单逻辑
    emailService.sendEmail();
    financialService.freeze();
    financialService.unfreeze();
    fileService.generateOrderFile();
}

那么有没有什么其他的方法呢?

方案

后面我们用到发布和监听模式:

csharp 复制代码
public void placeOrder(){
   //...正常订单逻辑
   applicationContext.publishEvent(Event orderPlacedEvent);
}

这个主体定下来之后便很少再做变动,使整个方法的职责尽可能地少,只关注订单本身的逻辑。之后我们再依据需求,对这个event进行监听。

less 复制代码
@Component
@EnableAsync
public class EmailListener{

  @EventListener
  @Async
  @Order(1)
  public void onEvent(Event event){
     //不同的监听器可以放在不同的类中,使类的职责尽可能地小比
     //比如从此处理邮件发送,他处处理冻结解冻
     emailService.sendEmail();
  }
}

红色部分可以额外的定义是否同步监听,同步监听可以认为是放在了一个方法内(如果有数据库事务,会默认加入同一事务),@Order注解会决定监听的顺序。

另外也可以使用 @TransactionalEventListener 替换 @EventListener, 比如,我需要在之前的order被正确的存入数据库(事务提交成功时),才执行监听:

less 复制代码
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, 
classes = Event .class)
@Async
public void onEvent(Event event){
  //...处理内容
}

这个时候注意如果阶段是phase = TransactionPhase.AFTER_COMMIT,那么必须得是异步,否则,语义是"等我自身被提交,我再去做监听",会是一个矛盾的内容。

思考

我们的思路,始终是围绕一个主题,即如何让代码能够经过最小的改动,牵涉最少的其他模块,去进行新需求的编写。

这也是为什么一些设计模式那么经典的原因。

相关推荐
我要神龙摆尾3 分钟前
IDEA 阅读插件
java·ide·intellij-idea·idea-plugs·plugs
涉密IT资质笔记44 分钟前
涉密人员脱密期管理规范:期限分级模型、就业限制边界与违规认定标准
java·服务器·前端·网络·数据库
mmsx1 小时前
Android Dialog 插槽模式:用一套壳统一全应用的弹窗风格
android·java·dialog·开发语言
u0111026751 小时前
工具页案例图如何编写 alt让图片说明与处理场景对应
java·前端·javascript·图像处理·人工智能·算法·ai作画
码上有光1 小时前
Linux:进程间通信——匿名管道通信、命名管道通信
android·java·linux·linux通信·匿名通信·命名通信
落魄实习生1 小时前
Agent Scope Java 2.x 系列【11】AgentState 与状态存储
java·开发语言·ai
Ivanqhz1 小时前
干涉图着色
java·服务器·网络·数据库·人工智能·深度学习
程序鉴定师2 小时前
2026年深圳小程序/App开发公司技术选型指南:从架构设计到交付标准全维度评估
java·小程序·uni-app·php·objective-c
用户094248568032 小时前
第20章:JVM G1 GC原理、日志与调优实战
java·jvm
打工仔折腾 AI2 小时前
把模型切换交给平台:用蓝耘智能路由搭建商品评论分析工具
java·服务器·前端·后端·python·性能优化·ai agent 实战