​​​​​​​​​​​​​​​​​​​​​订单接收不同业务消息设计_C18298182575的博客-CSDN博客

背景:

之前说过,订单消息通知的设计,主要通过多态+模板方法+策略实现

今天说的是通过自定义注解,做法是在子类上加上对应业务逻辑的枚举。

与之前设计的区别

1.同

定义抽象类:实现通用的方法

定义一个接口:让子类实现业务逻辑

子类存于map:都是把子类统一存于map,备用

2.异

抽象类:之前设计模式,抽象定义了抽象方法,之类业务处理实现抽象方法,现在没有,子类直接实现接口

,二者区别是什么:抽象方法及模板方法模式,子类与抽象类中通用实现方法有直接关系,抽象类中默认普通方法需要依赖抽象方法,有直接关系,或者说子类对消息或通知类参数,无法直接处理,需要抽象类普通方法处理一下,然后给子类处理。

接口:之前接口中处理定义业务接口外,还有一个标识区分每种子类的方法,子类各自实现,注解实现是通过子类注解中类型标识区分

map实现:之前是只是利用多态,注解实现通过:多态+反射。还有map存值不同:之前value只有一个值,注解value是个list。好乱,抛开实际业务讲设计就是扯淡,为什么是个list,因为相同的注解会存在于多个子类,即相同类型的业务通过多个子类来实现,为什么相同类型业务多个子类实现,这需要参数实际类型,或者设计方案,可能不需要这样做。选择之前类似订单的设计可能更好理解。

先看需求

视频直播-对接目睹,在目睹管理台创建直播,需要回调到后台落表数据,下图为通知参数,主要分为两层

1.namespace 代码第一层  处理的是 直播or回放

2.第二层 action,在第一层下细分,create or update or delete

设计时,第一层为不同业务项,子类实现,第二层,场景较多,可以通过定义枚举,通过

switch (actionEnum) {
case CREATE:
todo business
​​​​​​​case UPDATE_PAGE:
todo business

代码

回调入口:

@RestController
@RequestMapping(value = "/cb/mudu/v1/")
public class NotifyReceiverController {@Resourceprivate NotifySetting notifyAdaptor;@Resourceprivate NotifyReceiver notifyReceiver;@PostMapping("/notify")public BaseResult<String> onReceiver(@RequestBody NotifyEventContext data) {notifyReceiver.receive(data);return BaseResult.success("ok");}// ----------- notify setting --------------@PostMapping("/notify/url")public BaseResult<Boolean> setNotifyUrl(String url) {return BaseResult.success(notifyAdaptor.setNotifyUrl(url));}@GetMapping("/notify/url")public BaseResult<String> getNotifyUrl() {return BaseResult.success(notifyAdaptor.getNotifyUrl());}}

通知承接类


@Component
@Slf4j
public class NotifyReceiver {@Resourceprivate CompositeNotifyListener listener;public void receive(NotifyEventContext context) {log.info("Receive the nofity: {}", context);listener.handler(context);}}

实例初始化及处理分发类

Component
@DependsOn("springContextUtil")
@Slf4j
public class CompositeNotifyListener {private final Map<String, List<NotifyListener>> handlerMap = new ConcurrentHashMap<>();private ExecutorService executor = Executors.newFixedThreadPool(4, new ThreadFactory() {private AtomicInteger threadIndex = new AtomicInteger(0);@Overridepublic Thread newThread(Runnable r) {return new Thread(r, "NotifyExecutorThread_" + this.threadIndex.incrementAndGet());}});@PostConstructprivate void register() {Map<String, NotifyListener> map = SpringContextUtil.getBeans(NotifyListener.class);if (map == null) {log.info("No notify listener to register");return;}map.forEach((k, v) -> {NamespaceHandler handler = v.getClass().getAnnotation(NamespaceHandler.class);String namespace = handler.value().getNamespace();List<NotifyListener> list = handlerMap.get(namespace);if (list == null) {list = new ArrayList<NotifyListener>();handlerMap.put(namespace, list);}list.add(v);});}public void handler(NotifyEventContext context) {List<NotifyListener> listeners = handlerMap.get(context.getNamespace());if (CollectionUtils.isEmpty(listeners)) {log.warn("Not listener to handler the namespace#{} event");return;}listeners.stream().forEach(l -> executor.execute(() -> {try {l.handler(context);} catch (Exception e) {log.error("Execute the handler#{} exception", l.getClass(), e);}}));}}

接口

public interface NotifyListener {void handler(NotifyEventContext context);}

具体处理类

@Component
@NamespaceHandler(value = NamespaceEnum.ACTIVITY)
@Slf4j
public class ActivityListener extends AbstraceActivity implements NotifyListener {@Resourceprivate LiveService liveService;@Resourceprivate AuthorManagerService authorManagerService;@Resourceprivate MuduConfigProperties config;@Resourceprivate LiveSessionService liveSessionService;@Autowiredprivate RedisManager redisManager;@Autowiredprivate RemoveTagService removeTagService;@Overridepublic void handler(NotifyEventContext context) {if (context == null || !NamespaceEnum.ACTIVITY.getNamespace().equalsIgnoreCase(context.getNamespace())) {log.warn("Not belong to the {} namespace: {}", NamespaceEnum.ACTIVITY.getNamespace(),context.getNamespace());return;}ActionEnum actionEnum = ActionEnum.get(context.getAction());if (actionEnum == null) {log.warn("Not found the action#{}, so not handle", context.getAction());return;}switch (actionEnum) {case CREATE:Activity act = fetchActivity(context.getId());if (Objects.isNull(act)) {log.error("Not found the activity#{} from mudu", context.getId());break;}String authKey = setActivityAuth(context.getId(), config.getCustomVerifyUrl());log.info("mudu create_notify live: {}", JSON.toJSONString(act));AuthorManager authorManager = authorManagerService.selectByManager(new Long(act.getManager()));ResLiveDTO saveVO = ActivityConvertor.toRes(act, authKey);if (authorManager != null) {saveVO.setAuthorId(authorManager.getAuthorId());}liveService.saveLive(saveVO);break;case UPDATE_PAGE:Activity upAct = fetchActivity(context.getId());if (Objects.isNull(upAct)) {log.error("mudu update_notify exception failed to obtain activity, token may have expired");break;}log.info("mudu update_notify upAct: {}", JSON.toJSONString(upAct));ResLiveDTO upVO = ActivityConvertor.toRes(upAct, StringUtils.EMPTY);liveService.updateLive(upVO);break;case DELETE:liveService.deleteById(Long.parseLong(context.getId()));log.info("mudu delete_notify context: {}", JSON.toJSONString(context));break;case OPEN:liveService.closeOrOpenLive(Long.parseLong(context.getId()), IsShowEnum.SHOW.getValue());break;case CLOSE:liveService.closeOrOpenLive(Long.parseLong(context.getId()), IsShowEnum.NOT_SHOW.getValue());break;case STREAM:if (LiveStreamEnum.CLOSE.getValue() == context.getStatus()) {log.info("The live broadcast is closed, and the video is moved to the media library. context: {}",JSON.toJSONString(context));Activity activity = null;try {activity = fetchActivity(context.getId());log.info("Act:{}", activity);} catch (Exception e) {log.error("thread-error:", e);}try {ResLiveDTO startVO = new ResLiveDTO();startVO.setRoomId(Long.valueOf(context.getId()));startVO.setLiveStatus(LiveStatusEnum.LIVE_END.getValue());startVO.setCloseTime(new Date());liveService.updateLive(startVO);} catch (Exception e) {log.error("update live failed for#{}:", context.getId(), e);}try {liveSessionService.saveLiveSession(activity);} catch (Exception e) {log.error("Saving live session exception for#{}:", context.getId(), e);}}if (LiveStreamEnum.OPEN.getValue() == context.getStatus()) {log.info("live starting: {}", JSON.toJSONString(context));ResLiveDTO startVO = new ResLiveDTO();startVO.setRoomId(Long.valueOf(context.getId()));startVO.setLiveStatus(context.getStatus());liveService.updateLive(startVO);//删除tagtry {removeTagService.removeTagByActId(Integer.valueOf(context.getId()));} catch (Exception e) {log.error("remove tag failed by actId:{}", context.getId());}}break;default:break;}}}

消息通知设计,注解实现相关推荐

  1. openfire消息通知推送_APP消息推送功能之前端后台设计

    APP消息推送功能之前端后台设计 最近有不少小伙伴问APP消息推送功能,前端.后台如何设计的?消息系统的架构是什么样的?最近刚好做到后台消息推送这块,简单谈谈个人心得,欢迎拍砖. 消息推送是让自己的用 ...

  2. 消息通知系统详解2---后端设计

    消息通知系统详解1-通讯方式 消息通知系统详解2-后端设计 消息通知系统详解3-Netty 消息通知系统详解4-整合Netty和WebSocket 目录 整体设计 上线登录后向系统索取 在线时系统向接 ...

  3. JAVA社交平台项目第四天 消息通知系统

    第4章 - 消息通知系统 学习目标: 了解消息通知系统的业务场景 了解消息通知和即时通讯区别 实现消息通知微服务的基本功能 实现文章订阅和群发消息 实现文章点赞和点对点消息 了解基于数据库实现的通知系 ...

  4. 去哪儿网消息队列设计与实现

    去哪儿网近日在GitHub上开源了其内部广泛使用的消息队列(内部代号QMQ),本文从去哪儿网使用消息队列所碰到的各种问题出发探讨去哪儿网消息队列的设计与实现. 背景 2012年,随着公司业务的快速增长 ...

  5. html 消息通知功能,HTML5之消息通知的使用(Web Notification)

    关于 HTML5 ,写了不少文章,总觉得相关的高级 API 都得过一遍.系统的了解,站在更高的高度去思考问题,这样才能事半功倍. 一.先睹为快 我们先来尝试一个最简单的例子,打开 chrome 开发者 ...

  6. 印发 指南 通知_通知设计的综合指南

    印发 指南 通知 重点 (Top highlight) Peripheral messages in digital products, collectively known as notificat ...

  7. 用Java弹出创建新的消息通知

    首先创建JFrame作为弹出窗口. 在其中添加一些JLabel以包含信息,并在适当的位置分配它们,使其看起来像一条通知消息. 下面给出了示例代码: String message = 'You got ...

  8. java 观察者模式_重学 Java 设计模式:实战观察者模式「模拟类似小客车指标摇号过程,监听消息通知用户中签场景」...

    一.前言 知道的越多不知道的就越多 编程开发这条路上的知识是无穷无尽的,就像以前你敢说精通Java,到后来学到越来越多只想写了解Java,过了几年现在可能想说懂一点点Java.当视野和格局的扩大,会让 ...

  9. ActiveMQ学习总结(8)——消息队列设计精要

    2019独角兽企业重金招聘Python工程师标准>>> 消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步R ...

  10. 【kafka】消息队列设计精要

    1.概述 转载:消息队列设计精要 好文章,建议大家去看原文. 消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手 ...

最新文章

  1. 如何挖掘系统的业务价值
  2. android viewgroup 事件,android中viewgroup的事件传递分析
  3. PHP判断是否为手机客户端
  4. MFC 基础知识:对话框背景添加图片和按钮Button添加图片
  5. 推荐系统的封闭和禁锢问题
  6. php模糊搜索慢怎么办,MySQL中文模糊检索问题的解决方法_php
  7. 偏置面命令_UG10.0同步建模之移动面、删除面、替换面详解
  8. pytorch gather_GCN的简单实现(pytorch)
  9. python自动化办公要学多久-用 Python 自动化办公能做到哪些有趣或有用的事情?...
  10. 显示js对象所有属性和方法的函数
  11. GD32F130之DMA
  12. java实现支付宝网页扫码支付
  13. 【JZOJ B组】【NOIP2013模拟】Heaven Cow与God Bull
  14. 创业者两大特征:喜欢折腾与坚持不懈
  15. Android Pitfall - 扒一扒RadioGroup 和 RadioButton
  16. Exception: java.io.IOException: Keystore was tampered with, or password was incorrect
  17. mysql导出txt文件报错_mysql导入txt文件
  18. 软件测试 通用技术03 测试用例 黑盒测试用例设计方法 等价类划分法 边界值分析法 判定表法 场景法 功能图法 其他用例设计方法 用例设计方法综合选择
  19. Android 生成原生系统签名jks 与 keystore
  20. 数据结构(串,数组和广义表)

热门文章

  1. NA-NP-IE系列实验2
  2. 游侠原创:VMware ESXi 5安装图文教程
  3. 银行自动化监控系统应用
  4. 嵌入式开发之cmos---前端采集aptina cmos
  5. 防盗链Nginx设置图片防盗链,设置无效的请仔细看红字
  6. 移动健康应用观察:快速问医生的“Web 10年功”
  7. java sqlserver数据库连接_JAVA连接SQLserver数据库
  8. do_fork实现--下
  9. iptables 从入门到应用
  10. linux内核C -- 第08课:变参函数的格式检查——format