精讲23种设计模式-基于观察者模式~设计异步多渠道群发框架

文章目录

          • 一、观察者模式
            • 1. 观察者模式基本概念
            • 2. 观察者模式的应用场景
            • 3. 观察者模式的类图
          • 二、设计异步多渠道群发框架
            • 2.1. 定义消息观察者抽象接口
            • 2.2. 创建观察者
            • 2.3. 主题通知所有观察者
            • 2.4. 观察者注册
            • 2.5. 自定义线程池
            • 2.6. 签单通知入口
            • 2.6. 异步通知接口测试
            • 2.7. 依赖
          • 三、Spring事件通知
            • 3.1. 定义消息实体类
            • 3.2. 定义(邮件)事件通知
            • 3.3. 定义(短信)事件通知
            • 3.4. 签单同步通知入口
            • 3.5. 测试效果
            • 3.6. 开源项目

一、观察者模式
1. 观察者模式基本概念

一个对象状态改变,通知给其他所有的对象

2. 观察者模式的应用场景

Zk的事件监听、分布式配置中心刷新配置文件、业务中群发不同渠道消息

3. 观察者模式的类图

在这里插入图片描述

二、设计异步多渠道群发框架
2.1. 定义消息观察者抽象接口
package com.gblfy.observer;import com.alibaba.fastjson.JSONObject;/*** 定义消息观察者(ObServer)抽象接口** @author gblfy* @date 2022-03-15*/
public interface GblfyObServer {void sendMsg(JSONObject jsonObject);
}
2.2. 创建观察者

短信观察者

package com.gblfy.observer.impl;import com.alibaba.fastjson.JSONObject;
import com.gblfy.observer.GblfyObServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;/*** 定义(短信)事件通知** @author gblfy* @date 2022-03-15*/
@Slf4j
@Component
public class SmsObServer implements GblfyObServer {@Override@Async("customAsyncThreadPool")public void sendMsg(JSONObject jsonObject) {log.info("观察者模式发送->短信-->{}", jsonObject.toJSONString());}
}

邮件观察者

package com.gblfy.observer.impl;import com.alibaba.fastjson.JSONObject;
import com.gblfy.observer.GblfyObServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;/*** 定义(邮件)事件通知** @author gblfy* @date 2022-03-15*/
@Slf4j
@Component
public class EmailObServer implements GblfyObServer {@Override@Async("customAsyncThreadPool")public void sendMsg(JSONObject jsonObject) {log.info("观察者模式发送->邮件-->{}",jsonObject.toJSONString());}
}
2.3. 主题通知所有观察者
package com.gblfy.observer;import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.List;/*** 定义消注册中心,主题通知所有观察者** @author gblfy* @date 2022-03-15*/
@Component
public class GblfySubject {//观察者容器private List<GblfyObServer> obServerList = new ArrayList<>();/*** 添加观察者** @param gblfyObServer*/public void addObServer(GblfyObServer gblfyObServer) {obServerList.add(gblfyObServer);}/*** 通知所有的观察者** @param jsonObject*/public void notifyObServer(JSONObject jsonObject) {obServerList.stream().forEach(p -> p.sendMsg(jsonObject));}
}
2.4. 观察者注册

项目启动自动注册观察者

package com.gblfy.start;import com.gblfy.observer.GblfyObServer;
import com.gblfy.observer.GblfySubject;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;import java.util.Map;/*** 项目启动注册观察者** @author gblfy* @date 2022-03-15*/
@Component
public class StartService implements ApplicationRunner, ApplicationContextAware {@Autowiredprivate GblfySubject gblfySubject;//初始化上下文对象private ApplicationContext applicationContext;/*** 项目启动成功注册在观察着集合(ObServer的子类实例)** @param args* @throws Exception*/@Overridepublic void run(ApplicationArguments args) throws Exception {/*** 根据接口类获取相应bena对象,自动注册观察者* 1.使用spring获取ObServer下所有子类的bean对象* 2.将bean对象依次添加到gblfySubject观察者集合中即可*/Map<String, GblfyObServer> map = applicationContext.getBeansOfType(GblfyObServer.class);for (String key : map.keySet()) {GblfyObServer gblfyObServer = map.get(key);gblfySubject.addObServer(gblfyObServer);}}//获取上下文@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}
}
2.5. 自定义线程池
package com.gblfy.config;import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;/*** @Deacription 自定义异步线程池* @Author gblfy* @Date 2022-03-15 10:38**/
@Component
@EnableAsync
public class AsyncScheduledTaskConfig {@Bean("customAsyncThreadPool")public Executor customAsyncThreadPool() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();//最大线程数executor.setMaxPoolSize(100);//核心线程数executor.setCorePoolSize(10);//任务队列的大小executor.setQueueCapacity(10);//线程池名的前缀executor.setThreadNamePrefix("gblfy-signpolicy-asynnotify-");//允许线程的空闲时间30秒executor.setKeepAliveSeconds(30);//设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Beanexecutor.setWaitForTasksToCompleteOnShutdown(true);//设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住executor.setAwaitTerminationSeconds(60);/*** 拒绝处理策略* CallerRunsPolicy():交由调用方线程运行,比如 main 线程。* AbortPolicy():直接抛出异常。* DiscardPolicy():直接丢弃。* DiscardOldestPolicy():丢弃队列中最老的任务。*//*** 特殊说明:* 1. 这里演示环境,拒绝策略咱们采用抛出异常* 2.真实业务场景会把缓存队列的大小会设置大一些,* 如果,提交的任务数量超过最大线程数量或将任务环缓存到本地、redis、mysql中,保证消息不丢失* 3.如果项目比较大的话,异步通知种类很多的话,建议采用MQ做异步通知方案*/executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());//线程初始化executor.initialize();return executor;}
}
2.6. 签单通知入口
package com.gblfy.controller;import com.alibaba.fastjson.JSONObject;
import com.gblfy.observer.GblfySubject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;/*** 签单通知入口** @author gblfy* @date 2022-03-15*/
@Slf4j
@RestController
public class SignPolicyController {@Autowiredprivate GblfySubject gblfySubject;/*** 签单异步通知(短信、邮件等多种方式)** @return*/@GetMapping("/signPolicyToAsynNotify")public String signPolicy() {log.info("将签单信息保存数据库处理");JSONObject jsonObject = new JSONObject();jsonObject.put("sms", "1766666666");jsonObject.put("email", "1766@163.com");gblfySubject.notifyObServer(jsonObject);return "success";}
}
2.6. 异步通知接口测试
http://localhost:8080/signPolicyToAsynNotify

在这里插入图片描述

2.7. 依赖
 <!--字符串工具类--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version></dependency><!--数据json处理--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.79</version></dependency><!--SpringMVC--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
三、Spring事件通知
3.1. 定义消息实体类
package com.gblfy.entity;import org.springframework.context.ApplicationEvent;/*** 定义消息实体类** @author gblfy* @date 2022-03-15*/
public class SignPolicyMsgEntity extends ApplicationEvent {private String email;private String phone;private String userId;public SignPolicyMsgEntity(Object source) {super(source);}public SignPolicyMsgEntity(Object source, String email, String phone) {super(source);this.email = email;this.phone = phone;}@Overridepublic String toString() {return "email:" + email + ",phone:" + phone;}
}
3.2. 定义(邮件)事件通知
package com.gblfy.listener;import com.gblfy.entity.SignPolicyMsgEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;/*** 定义(邮件)事件通知** @author gblfy* @date 2022-03-15*/
@Component
@Slf4j
public class EmailListener implements ApplicationListener<SignPolicyMsgEntity> {@Overridepublic void onApplicationEvent(SignPolicyMsgEntity event) {log.info("eamil:->{}", event.toString());}
}
3.3. 定义(短信)事件通知
package com.gblfy.listener;import com.gblfy.entity.SignPolicyMsgEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;/*** 定义(短信)事件通知** @author gblfy* @date 2022-03-15*/
@Component
@Slf4j
public class SmsListener implements ApplicationListener<SignPolicyMsgEntity> {@Overridepublic void onApplicationEvent(SignPolicyMsgEntity event) {log.info("sms:->{}", event.toString());}}
3.4. 签单同步通知入口
@Autowired
private ApplicationEventPublisher applicationEventPublisher;/*** 签单同步通知(短信、邮件等多种方式)* 使用spring事件通知** @return*/@GetMapping("/signPolicyToSyncNotify")public String signPolicyToSyncNotify() {log.info("将签单信息保存数据库处理");SignPolicyMsgEntity signPolicyMsgEntity = new SignPolicyMsgEntity(this, "1766@163.com", "1766666666");applicationEventPublisher.publishEvent(signPolicyMsgEntity);return "success";}
3.5. 测试效果
http://localhost:8080/signPolicyToSyncNotify

在这里插入图片描述

3.6. 开源项目

https://gitee.com/gblfy/design-pattern/tree/observer-mode/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/515883.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

君子动手不动口,阿里云喊你做云上体验官啦!

想要免费搭建云上博客&#xff1f;想要玩转全云端开发&#xff1f;想要挑战AI经典命题&#xff1f;想要7天进阶成为云计算专家&#xff1f;想要初始化你的云原生工程&#xff1f;快来阿里云 Hands-on Labs&#xff01; Hands-on Labs 是阿里云全新推出的云上动手实验室&#x…

我是Redis,MySQL大哥被我害惨了!

来源 | 编程技术宇宙责编 | 晋兆雨头图 | 付费下载于视觉中国我是Redis你好&#xff0c;我是Redis&#xff0c;一个叫Antirez的男人把我带到了这个世界上。说起我的诞生&#xff0c;跟关系数据库MySQL还挺有渊源的。在我还没来到这个世界上的时候&#xff0c;MySQL过的很辛苦&a…

联手友盟+打造云上数据增长“样板间”, 好兔视频成功逆势突围

前言&#xff1a;更多关于数智化转型、数据中台内容可扫码加群一起探讨 阿里云数据中台官网 https://dp.alibaba.com/index &#xff08;作者&#xff1a;友盟&#xff09; “消费升级”是近年来的中国消费市场热门词汇&#xff0c;消费升级的同时也驱动了内容消费升级。在这样…

SpringBoot 使用 Caffeine 本地缓存

文章目录一、本地缓存介绍二、缓存组件 Caffeine 介绍2.1. Caffeine 性能2.2. Caffeine 配置说明2.3. 软引用与弱引用三、SpringBoot 集成 Caffeine 方式一3.1. Maven 引入相关依赖3.2. 配置缓存配置类3.3. 定义实体对象3.4. 定义服务接口类3.5. 定义服务接口实现类3.6. Caffei…

《Istio 从懵圈到熟练:二分之一活的微服务》

作者 | 声东 阿里云售后技术专家 <关注阿里巴巴云原生公众号&#xff0c;回复 排查 即可下载电子书> 《深入浅出 Kubernetes》一书共汇集 12 篇技术文章&#xff0c;帮助你一次搞懂 6 个核心原理&#xff0c;吃透基础理论&#xff0c;一次学会 6 个典型问题的华丽操作…

为了追求更快,CPU、内存、I/O都做了哪些努力?

来源 | 编程技术宇宙责编 | 晋兆雨头图 | 付费下载于视觉中国背景曾经&#xff0c;我面试的时候有两个最怕的。一怕问算法&#xff0c;二怕问高并发。算法这个&#xff0c;自从刷了不少LeetCode&#xff0c;发现还是有套路可循的&#xff0c;虽不敢说算法能力有多强&#xff0c…

神结合!一招玩转K8s和微服务治理

发布会传送门 进入直播间还有好礼等你拿&#xff01; EDAS产品免费试用&#xff1a;https://www.aliyun.com/activity/middleware/edaspromotiononmay 首届云原生编程挑战赛正式开战&#xff01;立即报名瓜分330000现金奖&#xff1a;https://tianchi.aliyun.com/specials/p…

精讲23种设计模式-基于装饰模式~设计多级缓存框架

文章目录一、装饰模式1. 回顾多级缓存基本概念2. 装饰模式基本的概念3. 装饰模式应用场景4. 装饰者模式定义5. 基于Map手写Jvm内置缓存二、手写一级与二级缓存2.1. redis工具类2.2. 实体类2.3. 接口2.4. 数据库脚本2.5. 测试案例2.6. 测试效果分享三、设计多级缓存框架3.1. 缓存…

阿里云EDAS 3.0重磅发布,无侵入构建云原生应用

发布会传送门 进入直播间还有好礼等你拿&#xff01; EDAS产品免费试用&#xff1a;https://www.aliyun.com/activity/middleware/edaspromotiononmay 首届云原生编程挑战赛正式开战&#xff01;立即报名瓜分330000现金奖&#xff1a;https://tianchi.aliyun.com/specials/p…

二维数组的偏移量

数组的偏移量&#xff1a; 数组空间起始位置的偏移值。 公式&#xff1a; 例题&#xff1a; 结合图片分析例题和公式&#xff1a;

Akamai “三驾马车”,如何应对疫情后新场景形态下的新考验?

2020年10月14日&#xff0c;CDN行业领头羊、负责提供安全数字化体验的智能边缘平台Akamai&#xff08;阿卡迈技术&#xff09;发布了其边缘计算、媒体交付和安全方面的产品组合的多项更新。其中在Akamai智能边缘&#xff08;Akamai Intelligent Edge&#xff09;、媒体交付、应…

如何使用MaxCompute Spark读写阿里云Hbase

背景 Spark on MaxCompute可以访问位于阿里云VPC内的实例&#xff08;例如ECS、HBase、RDS&#xff09;,默认MaxCompute底层网络和外网是隔离的&#xff0c;Spark on MaxCompute提供了一种方案通过配置spark.hadoop.odps.cupid.vpc.domain.list来访问阿里云的vpc网络环境的Hba…

elementui更改el-table表头背景颜色和字体颜色

博主在使用elementui中的el-table时感觉默认表格样式实在过于简洁&#xff0c;尤其表头与表格内容之间区别较小&#xff0c;不利于辨认&#xff0c;降低了用户体验。如图所示&#xff1a; 于是&#xff0c;博主尝试更改一下表头的背景颜色和字体颜色&#xff0c;方法如下&…

idea 提升幸福感 常用设置(重装机配置)

1.常用快捷键 alt 7 展示类的方法 CtrlH 查看当前所选类的继承关系 CtrlShift上下键 上下移动整行 2.自动导包&#xff1a; 3.自动创建 serialVersionUID IDEA 自动给实现了 Serializable 接口的类创建 serialVersionUID 4.类与方法注释快捷键设置 方法注释模板设置 类与方…

ClickHouse内核分析-MergeTree的Merge和Mutation机制

注&#xff1a;以下分析基于开源 v19.15.2.2-stable 版本进行 引言 ClickHouse内核分析系列文章&#xff0c;继上一篇文章 MergeTree查询链路 之后&#xff0c;这次我将为大家介绍MergeTree存储引擎的异步Merge和Mutation机制。建议读者先补充上一篇文章的基础知识&#xff0…

el-table中奇偶行背景色显示不同的颜色

默认样式 深色主题 border ref"singleTable" highlight-current-row current-change"handleCurrentChange" :row-class-name"tableRowClassName" :header-cell-style"{background:#004d8c,color:#FFFFFF}"事件方法 //奇偶行背景色不…

阿里云专属数据库,重新定义云数据库新形态

阿里云数据库专属集群专属链接 云专属数据库&#xff0c;重新定义云数据库新形态 数据库是一个有着超过40年历史的悠久行业&#xff0c;前期一直被传统的如Oracle等少数几家厂商把持。云计算的先行者AWS在2009年率先推出RDS服务&#xff08;Relational Database Service &…

软考零散知识点

网络命令 多态 强制多态&#xff1a;数字类型运算的自动拆装箱 过载多态&#xff1a;子类重写父类的方法 参数多态&#xff1a;方法的重载 包含多态&#xff1a;父类的引用指向子类的对象 主存和cache映射 RAID RAID RAID0&#xff1a;无冗余备份&#xff0c;带化。每条数据…

ServiceMesh最火项目:Istio架构解析

Istio 是一个开源的服务网格&#xff0c;可为分布式微服务架构提供所需的基础运行和管理要素。随着各组织越来越多地采用云平台&#xff0c;开发者必须使用微服务设计架构以实现可移植性&#xff0c;而运维人员必须管理包含混合云部署和多云部署的大型分布式应用。Istio 采用一…

docker-compose 实战案例

文章目录一、Compose入门案例1. 依赖2. 实体类3. mapper接口4. 启动类5. yml配置6. 测试案例7. 打包二、制作 DockerFile和docker-compose.yml2.1. 制作 DockerFile2.2. docker-compose.yml三、打包部署3.1. 资料上传3.2. 启动docker-compose3.3. 创建表3.4. 接口测试3.5. 数据…