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一站式入门使用
从源码编译、部署broker、部署namesrv,使用java客户端首发消息等一站式入门RocketMQ。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
|
算法
贪心算法入门典型案例
在N行M列的正整数矩阵中,要求从每行中选出1个数,使得选出的总共N个数的和最大。输入:第一行两个正整数N和M,用空格隔开,表示行数和列数 第2行到第N+1行,每行M个用空格隔开的整数 ,表示矩阵 输出最大总和 1 #include 2 #include 3 #include 4 5 ...
1049 0
|
9月前
|
前端开发
项目实战典型案例22——原型图的面向对象思路
项目实战典型案例22——原型图的面向对象思路
49 1
|
安全 中间件 测试技术
【面试高频】给你一句话需求,让你设计测试用例,该怎么做?
【面试高频】给你一句话需求,让你设计测试用例,该怎么做?
【面试高频】给你一句话需求,让你设计测试用例,该怎么做?
|
Rust Kubernetes 测试技术
Krustlet 入手案例
本文将对基于 Kind 部署 Krustlet 并实践 Demo 应用
361 0
|
设计模式 算法 Java
《刻意练习》:以学习编程为例
《刻意练习》是一本神奇的魔法书,它用大量的事实案例和数据来证明了刻意练习能给一个人带来的巨大改变。更为难能可贵的是,它不仅仅只是介绍刻意练习的好处,还给读者介绍了刻意练习的方法和注意事项,可以说是干货满满的一本书。
356 0
|
机器学习/深度学习 存储 算法
编程面试的10大算法概念汇总
以下是在编程面试中排名前10的算法相关的概念,我会通过一些简单的例子来阐述这些概念。由于完全掌握这些概念需要更多的努力,因此这份列表只是作为一个介绍。本文将从Java的角度看问题,包含下面的这些概念:
113 0
|
SQL 数据采集 分布式计算
用户画像有什么用?怎样用?6个场景案例给你讲明白
在大数据分析中,对用户行为进行分析挖掘又是一个重要的方向,通过对用户行为进行分析,企业可以了解用户从哪里来,进入平台后进行了哪些操作,什么情况下进行了下单付款,用户的留存、分布情况是怎样的等。
|
机器学习/深度学习 算法 搜索推荐
对推荐算法演化的几点体会
最近一段时间,由于工作需要一直在研究推荐算法。 通过对互联网信息的搜刮和对现有开源推荐算法的实践,总结出一些心得 遂吐个槽,发表出来与广大网友探讨,希望能得到应用推荐的正确姿势 先说问题吧: 目前推荐算法存在的问题 1.
12240 0
|
存储 SQL 前端开发
【自然框架】——思路、结构、特点的介绍(初稿,欢迎大家多提意见)
开场白  面向过程:面向过程是“写代码”,根据客户提出来的需求来写代码,包括函数。一步一步的写,都写完了,功能也就实现了。   面向对象:面向对象是“做设计”,先不考虑细节,而是先做总体设计。都设计好了,再去实现细节。
1027 0
|
关系型数据库 数据库
我写项目的思路和“自然架构”
我写项目的思路       三层的思路是要把页面(UI、数据显示)、业务逻辑、数据处理(也叫持久化)分离开来处理,思路自然是好的,但是一到了实际应用中,好多人就会遇到一点小小的问题,于是产生了好多的争论。
928 0