pmq学习一-一些典型的使用和套路

简介: pmq是信也科技开源的一款消息中间件,虽然没有RocketMQ和Kafka出名,但是里面的代码还是有值得我们学习的地方的。pmq的源码里面很多套路还是值得学习的,说实话,这些都是可以用到项目里面的。下面的代码来源于pmq。首先安装好maven、mysql,对下载下拉的包进行打包:如果遇到时区问题,则可以调整时区问题。1.MqBootstrapListener 观察者模式的使用

pmq是信也科技开源的一款消息中间件,虽然没有RocketMQ和Kafka出名,但是里面的代码还是有值得我们学习的地方的。

pmq的源码里面很多套路还是值得学习的,说实话,这些都是可以用到项目里面的。下面的代码来源于pmq。

首先安装好maven、mysql,对下载下拉的包进行打包:

如果遇到时区问题,则可以调整时区问题。

1.MqBootstrapListener 观察者模式的使用

/*** mqBootstrap监听 实现 上下文监听 观察者模式*/@ComponentpublicclassMqBootstrapListenerimplementsApplicationListener<ContextRefreshedEvent>, Ordered {
privatestaticfinalLoggerlog=LoggerFactory.getLogger(MqBootstrapListener.class);
privatestaticbooleanisInit=false;
@AutowiredprivateReportServicereportService;
@OverridepublicintgetOrder() {
// TODO Auto-generated method stubreturnOrdered.LOWEST_PRECEDENCE;
   }
//使用观察者模式重写onApplicationEvent方法@OverridepublicvoidonApplicationEvent(ContextRefreshedEventevent) {
//判断是否初始化了,如果初始化,则启动定时任务if (!isInit) {
try {
startTimer();
startPortalTimer();
//注册reportreportService.registerReport();
//将其进行初始化isInit=true;
log.info("mq初始化成功!");
         } catch (Exceptione) {
log.error("mq初始化异常", e);
throwe;
         }
      }
   }
//启动portal定时任务privatevoidstartPortalTimer() {
Map<String, PortalTimerService>startedServices=SpringUtil.getBeans(PortalTimerService.class);
if (startedServices!=null) {
startedServices.entrySet().forEach(t1-> {
try {
t1.getValue().startPortal();
log.info(t1.getKey() +"启动完成!");
            } catch (Exceptione) {
log.error(t1.getKey() +"启动异常!", e);
            }
         });
      }
   }
//启动定时任务privatevoidstartTimer() {
Map<String, TimerService>startedServices=SpringUtil.getBeans(TimerService.class);
if (startedServices!=null) {
startedServices.entrySet().forEach(t1-> {
try {
t1.getValue().start();
log.info(t1.getKey() +"启动完成!");
            } catch (Exceptione) {
log.error(t1.getKey() +"启动异常!", e);
            }
         });
      }
   }
}

观察者模式,通常我们进行配置或者将token放入到配置里面的时候,可以使用,而这样可以实时更新。

2.CAS的使用和volitale的使用,使用volitale的时候会考虑到读写屏障。使用@PostConstruct后置构造,这个类似于实现实现InitializingBean,重写AfterPropertiesSet。当然也可以基于ApplicationEvent实现,观察者模式。或者使用后置处理器。

/*** 数据report服务*/@ComponentpublicclassDbReportService {
//消息服务@AutowiredprivateMessage01Servicemessage01Service;
//数据节点服务@AutowiredprivateDbNodeServicedbNodeService;
//原子对象 mapprivateAtomicReference<Map<String, Integer>>conMapRef=newAtomicReference<Map<String, Integer>>(
newHashMap<>());
//线程池privateExecutorServiceexecutorService=Executors         .newSingleThreadExecutor(SoaThreadFactory.create("DbReportService", true));
//运行为trueprivatevolatilebooleanisRunning=true;
//度量指标privatevolatileMap<String, Boolean>metricMap=newConcurrentHashMap<>();
//启动标识privateAtomicBooleanstartFlag=newAtomicBoolean(false);
//后置构造注解@PostConstructpublicvoidreport() {
//使用cas进行比较if (startFlag.compareAndSet(false, true)) {
//线程池服务提交服务executorService.submit(newRunnable() {
@Overridepublicvoidrun() {
while (isRunning) {
Map<Long, DbNodeEntity>dbNodeMap=dbNodeService.getCache();
Map<String, DbNodeEntity>dataSourceMap=newHashMap<>();
Map<String, Integer>conMap=newHashMap<>();
try {
for (longdbId : dbNodeMap.keySet()) {
if (!dataSourceMap.containsKey(dbNodeMap.get(dbId).getIp())) {
dataSourceMap.put(dbNodeMap.get(dbId).getIp(), dbNodeMap.get(dbId));
                        }
                     }
for (Stringip : dataSourceMap.keySet()) {
message01Service.setDbId(dataSourceMap.get(ip).getId());
//连接计数intconCount=message01Service.getConnectionsCount();
conMap.put(ip, conCount);
if (!metricMap.containsKey(ip)) {
//System.out.println(ip);metricMap.put(ip, true);
//度量单例 获取度量注册MetricSingleton.getMetricRegistry().register("mq.ip.con.count?ip="+ip,
newGauge<Integer>() {
@OverridepublicIntegergetValue() {
if (conMapRef.get().containsKey(ip)) {
returnconMapRef.get().get(ip);
                                       } else {
return0;
                                       }
                                    }
                                 });
                        }
                     }
conMapRef.set(conMap);
                  } catch (Exceptione) {
// TODO: handle exception                  }
Util.sleep(10000);
               }
            }
         });
      }
   }
//销毁前将运行状态变成false,同时将线程池关闭@PreDestroyprivatevoidclose() {
isRunning=false;
executorService.shutdown();
   }
}

3.使用过滤器:实现filer接口,同时重写init方法、doFilter方法、destroy。通常会在doFilter进行逻辑处理。以前我写过一个url的拼接,基于CAS的重定向url拼接,当时也是基于filter实现的,当时也是在doFilter中实现的。

/*** 权限过滤器*/@Order(1)
@WebFilter(filterName="WebAuthFilter", urlPatterns="/*")
publicclassAuthFilterimplementsFilter {
Loggerlog=LoggerFactory.getLogger(this.getClass().getName());
@AutowiredprivateMessage01Servicemessage01Service;
@AutowiredUserInfoHolderuserInfoHolder;
@Overridepublicvoidinit(FilterConfigfilterConfig) throwsServletException {
   }
@OverridepublicvoiddoFilter(ServletRequestreq, ServletResponseresp, FilterChainchain)
throwsIOException, ServletException {
HttpServletRequestrequest= (HttpServletRequest) req;
HttpServletResponseresponse= (HttpServletResponse) resp;
Stringuri=request.getRequestURI();
if (skipUri(uri)) {
chain.doFilter(request, response);
      } else {
try {
Cookiecookie=CookieUtil.getCookie(request, "userSessionId");
if (cookie==null) {
response.sendRedirect("/login");
            } else {
StringuserId=DesUtil.decrypt(cookie.getValue());
userInfoHolder.setUserId(userId);
chain.doFilter(request, response);
            }
         } catch (Exceptione) {
log.error("login fail", e);
response.sendRedirect("/login");
         } finally {
message01Service.clearDbId();
userInfoHolder.clear();
         }
      }
   }
privateList<String>skipUrlLst=newArrayList<>();
publicAuthFilter() {     
skipUrlLst=Arrays.asList("/login", ".js", ".css", ".jpg", ".woff", ".png", "/auth" ,"/cat","/hs","/message/getByTopic");
   }
privatebooleanskipUri(Stringuri) {
for(Stringt : skipUrlLst){
if(uri.indexOf(t)!=-1){
returntrue;
         }
      }
returnfalse;
   }
@Overridepublicvoiddestroy() {
// TODO Auto-generated method stub   }
}

4.获取用户信息,使用threadLocal

/*** 默认用户信息holder*/@ServicepublicclassDefaultUserInfoHolderimplementsUserInfoHolder {
@AutowiredprivateUserProviderServiceuserProviderService;
//使用threadLocal,用户idLocalprivateThreadLocal<String>userIdLocal=newThreadLocal<>();
//获取用户信息@OverridepublicUserInfogetUser() {
StringuserId=userIdLocal.get();
Map<String, UserInfo>mapUser=userProviderService.getUsers();
if (mapUser.containsKey(userId)) {
returnmapUser.get(userId);
      }
returnnull;
   }
//获取用户id@OverridepublicStringgetUserId() {
returnuserIdLocal.get();
   }
//设置用户id@OverridepublicvoidsetUserId(StringuserId) {
userIdLocal.set(userId);
   }
//执行清理操作Thread@Overridepublicvoidclear() {
userIdLocal.remove();
   }
}

这个在我们项目里面也是这样使用的,这里可以进行改进,可以将token放入到用户信息中去,使用观察者模式。

5.cookie工具类:

/*** cookie工具类*/publicclassCookieUtil {
//获取用户名称publicstaticStringgetUserName(HttpServletRequestrequest){
//获取一个cookie数组Cookie[] cookies=request.getCookies();
StringuserName="";
if (cookies!=null) {
//获取cookieCookiecookie=getCookie(request, "userSessionId");
if (cookie==null) {
return"";
            }
try {
//返回对数据进行DES加密的数据returnDesUtil.decrypt(cookie.getValue());
            } catch (Exceptione) {
return"";
            }
        }
returnuserName;
    }
//获取cookiepublicstaticCookiegetCookie(HttpServletRequestrequest, Stringkey) {
Cookie[] cks=request.getCookies();
if (cks!=null) {
for (Cookietemp : cks) {
if (temp.getName().equals(key))
returntemp;
            }
        }
returnnull;
    }
}

常用的获取cooike的工具类,够实用。当然里面还有很多值得学习的地方,慢慢学习吧!

相关实践学习
快速体验阿里云云消息队列RocketMQ版
本实验将带您快速体验使用云消息队列RocketMQ版Serverless系列实例进行获取接入点、创建Topic、创建订阅组、收发消息、查看消息轨迹和仪表盘。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
|
7月前
|
机器学习/深度学习 人工智能 缓存
中国AI又赢了!成本砍到前代1/10!DeepSeek V4为什么能这么便宜?
DeepSeek V4以自研CSA+HCA混合稀疏注意力架构,实现百万上下文算力需求降至前代1/10;KV缓存压缩至7%,消费级显卡即可运行;全量开源、免费商用。精度不妥协——MRCR检索准确率83.5%,超越Gemini 3.1 Pro,真正让长文本AI从“奢侈品”变为普惠“水电煤”。(239字)
1103 2
|
5月前
|
Linux 程序员 数据格式
【2026最新】Notepad++下载、安装和使用一篇搞定(附中文版安装包)
Notepad++ 是一款免费开源、轻量高效的 Windows 文本编辑器,支持 C/Python/HTML 等 80+ 语言语法高亮、代码折叠、正则替换、编码转换及插件扩展,专为程序员与文本处理用户打造,完美替代系统记事本。(239字)
63508 12
|
IDE Java 编译器
java编程最基础学习
Java入门需掌握:环境搭建、基础语法、面向对象、数组集合与异常处理。通过实践编写简单程序,逐步深入学习,打牢编程基础。
554 1
|
7月前
|
人工智能 自然语言处理 API
技术实战:基于CLI与AgentSkill 构建工业级AI影视解说自动化链路
本文介绍2026年AI影视解说新范式:基于narrator-ai-cli与Skill架构的本地优先自动化Pipeline。支持一行命令或自然语言指令,打通视频理解、文案生成、配音剪辑全流程;兼顾数据隐私(GB级素材本地处理)与云端智能(大模型文案/TTS),实现工业化、可扩展的短视频量产。
|
8月前
|
人工智能 安全 API
两步上手龙虾AI!阿里云OpenClaw极简部署,轻松拥有专属AI助理!
阿里云OpenClaw(龙虾AI)是开源、本地优先的AI自动化代理,支持零代码、两步部署:5分钟即可拥有隐私可控、能自动执行文件管理、数据处理等真实任务的专属“数字员工”,告别AI只会聊天不落地的痛点。
1252 1
|
9月前
|
运维 监控 Shell
测试日志里的海量ERROR?用RAG架构训练一个专属日志分析师
本文介绍如何用RAG(检索增强生成)构建专属日志分析系统:通过日志清洗、混合检索(BM25+向量)、结构化提示词与闭环反馈,让大模型摆脱“幻觉”,精准定位真实故障。不依赖正则或标注,将老师傅经验沉淀为可复用的向量知识库。
|
12月前
|
人工智能 监控 算法
AI测试开发工程师面试指南:20个核心技术问题及思路解析
霍格沃兹测试开发学社总结AI测试开发岗位面试要点。面试重点考察模型验证、性能优化、MLOps落地等工程能力。建议结合项目经验,展示从需求到上线的全流程实践经验,并通过量化指标体现技术价值。同时需掌握特征工程、模型监控及前沿技术应用,系统提升综合竞争力。
|
12月前
|
数据采集 JSON 前端开发
从Bing图片搜索JSON API直接获取数据
从Bing图片搜索JSON API直接获取数据
|
设计模式 搜索推荐 测试技术
提示词工程的十大认知误区
本文将列举一些提示工程认知和创作方面的认知误区,并分享了作者的一些见解,希望能够为读者提供启发。
850 35
|
设计模式 Java 关系型数据库
设计模式:工厂方法模式(Factory Method)
工厂方法模式是一种创建型设计模式,通过将对象的创建延迟到子类实现解耦。其核心是抽象工厂声明工厂方法返回抽象产品,具体工厂重写该方法返回具体产品实例。适用于动态扩展产品类型、复杂创建逻辑和框架设计等场景,如日志记录器、数据库连接池等。优点包括符合开闭原则、解耦客户端与具体产品;缺点是可能增加类数量和复杂度。典型应用如Java集合框架、Spring BeanFactory等。