精讲23种设计模式-基于观察者模式~设计异步多渠道群发框架
生活随笔
收集整理的這篇文章主要介紹了
精讲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/signPolicyToAsynNotify2.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/signPolicyToSyncNotify3.6. 開源項目
https://gitee.com/gblfy/design-pattern/tree/observer-mode/
總結
以上是生活随笔為你收集整理的精讲23种设计模式-基于观察者模式~设计异步多渠道群发框架的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: docker nginx:1.21.4
- 下一篇: oracle用户编辑文件中文乱码