文章目录

  • 一、观察者模式
    • 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/

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

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

    文章目录 一.装饰模式 1. 回顾多级缓存基本概念 2. 装饰模式基本的概念 3. 装饰模式应用场景 4. 装饰者模式定义 5. 基于Map手写Jvm内置缓存 二.手写一级与二级缓存 2.1. red ...

  2. 精讲23种设计模式-基于责任链模式~构建企业级风控系统

    文章目录 一.责任链 1. 责任链基本概念 2. 定义 3. 关键要点 4. 责任链模式优缺点 5. 责任链模式类结构图 6. 网关权限控制责任链模式 二.构建企业级风控系统 2.1. 定义公共抽象任 ...

  3. 精讲23种设计模式-策略模式~聚合短信服务和聚合支付服务

    文章目录 一.设计模式 1. 为什么需要使用设计模式 2. 设计模式的分类 3. 什么是策略模式 4. 为什么叫做策略模式 5. 策略模式优缺点 6. 策略模式应用场景 7. Spring框架中使用的 ...

  4. 李建忠讲23种设计模式笔记-上

    前两天在B站看了李建忠老师讲23种设计模式的系列视频,收获颇丰.设计模式是前人的智慧和经验的总结,需要我们反复地学习.在实践中体会其蕴含的设计原则和设计思想.李老师按照封装变化将23种设计模式分成组件 ...

  5. 【23种设计模式】观察者模式(Observer Pattern)

    个人主页:金鳞踏雨 个人简介:大家好,我是金鳞,一个初出茅庐的Java小白 目前状况:22届普通本科毕业生,几经波折了,现在任职于一家国内大型知名日化公司,从事Java开发工作 我的博客:这里是CSD ...

  6. 23种设计模式之观察者模式

    观察者模式的定义 定义: 定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新 通俗的说, 就是一个类的某个条件满足时, 会调用一系列定义好的方法 其 ...

  7. Java 23种设计模式(1.设计模式概念和UML)

    1. 设计模式概念 软件设计模式(Software Design Pattern),又称设计模式 是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结 1.1 设计模式学习必要性理由 设 ...

  8. 终于有人将23种设计模式与七大设计原则整理明白了!!!

  9. 【Go实现】实践GoF的23种设计模式:命令模式

    上一篇:[Go实现]实践GoF的23种设计模式:代理模式 简单的分布式应用系统(示例代码工程):https://github.com/ruanrunxue/Practice-Design-Patter ...

最新文章

  1. 人脸检测--Scale-Aware Face Detection
  2. leetcode算法题--Lemonade Change
  3. MSSQL2000 数据库文件迁移到 MSSQL2005 可能要用的一些命令
  4. 148. Leetcode 455. 分发饼干 (贪心算法-基础题目)
  5. 神经网络 | BP神经网络介绍(附源代码:BP神经网络-异或问题)
  6. Go变量地址值和指针的关系
  7. kafka修改分区数_Kafka笔记
  8. apache 目录网站显示indexs
  9. leetcode剑指 Offer 63. 股票的最大利润(动态规划)
  10. 神经网络不应视为模型,推理过程当为机器学习问题一等公民
  11. 优雅的封装ajax,含跨域
  12. Pop3_解决PKIX:unable to find valid certification path to requested target 的问题
  13. 管家婆普及版_昆明逸马软件 — 管家婆普及版新手入门指南
  14. zemax输出ies_基于ZEMAX的光学设计教程(第2版)
  15. Eclipse 启动时提示loading workbench错误并提示查看.log
  16. QT自定义Widget实现鼠标拖动窗口移动位置及鼠标拖拽窗口边缘窗口大小改变
  17. mysqldb python linux,Linux下安装 MySQLdb模块
  18. Android编译命令m、mm、mmm区别及工程搭建示例
  19. android 电池检测软件,电池检测软件下载-电池检测 安卓版v1.1.0-PC6安卓网
  20. ROS中的坐标系规定及数据单位

热门文章

  1. 加速博士生失败的10种路径
  2. 校长回应8名考生放弃清华北大:不喜欢学医才去其他
  3. 干货:调度算法的价值与阿里的应用实践(内有赛事福利)
  4. 生活中常见的电器,他们的工作原理你知道吗?
  5. Linux网络编程常见面试题
  6. 堆排序和归并排序 java代码实现
  7. 面向切面编程--AOP
  8. windows稀疏文件
  9. Spark 运行内存不足Not enough space to cache rdd in memory,Container killed by YARN for exceeding memory
  10. ros(4)话题的自定义消息