下面设计实现的是:交换机Hlr指令处理任务模块。当然,在后续的业务发展过程中,还可能出现,其他类型指令的任务处理,所以根据“开闭”原则的定义,要抽象出一个接口类:BusinessEvent

发布时间:2026/10/4 12:23:24

下面设计实现的是:交换机Hlr指令处理任务模块。当然,在后续的业务发展过程中,还可能出现,其他类型指令的任务处理,所以根据“开闭”原则的定义,要抽象出一个接口类:BusinessEvent /** * filename:BusinessEvent.java * * Newland Co. Ltd. All rights reserved. * * Description:业务事件任务接口定义 * author tangjie * version 1.0 * */ package newlandframework.batchtask.model; public interface BusinessEvent { // 执行具体批处理的任务 public int execute(Integer userId); }然后具体的Hlr指令发送任务模块HlrBusinessEvent要实现这个接口类的方法完成用户停复机Hlr指令的派发。代码如下/** * filename:HlrBusinessEvent.java * * Newland Co. Ltd. All rights reserved. * * Description:Hlr指令派发任务接口定义 * author tangjie * version 1.0 * */ package newlandframework.batchtask.model; import org.apache.commons.lang.math.RandomUtils; public class HlrBusinessEvent implements BusinessEvent { // 交换机上的指令执行成功失败标识0表示成功 1表示失败 public final static int TASKSUCC 0; public final static int TASKFAIL 1; private final static int ELAPSETIME 1000; Override public int execute(Integer userId) { // 这里为了举例,随机产生1000以内的随机数 int millis RandomUtils.nextInt(ELAPSETIME); // 简单模拟往交换机发送停机/复机的指令 try { Thread.sleep(millis); String strContent String.format( 线程标识[%s]用户标识:[%d]执行交换机指令工单耗时:[%d]毫秒, Thread .currentThread().getName(), userId, millis); System.out.println(strContent); // 这里为了演示直接简单根据随机数是不是偶数简单模拟交换机指令执行的结果 return (millis % 2 0) ? TASKSUCC : TASKFAIL; } catch (InterruptedException e) { e.printStackTrace(); return TASKFAIL; } } }实际运行情况中我们可能要监控一下指令发送的时长于是再设计一个针对Hlr指令发送任务模块HlrBusinessEvent切面嵌入代理的Hlr指令时长计算代理类HlrBusinessEventAdvisor具体的代码如下/** * filename:HlrBusinessEventAdvisor.java * * Newland Co. Ltd. All rights reserved. * * Description:Hlr指令派发时长计算代理类 * author tangjie * version 1.0 * */ package newlandframework.batchtask.model; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.lang.time.StopWatch; public class HlrBusinessEventAdvisor implements MethodInterceptor { public HlrBusinessEventAdvisor() { } Override public Object invoke(MethodInvocation invocation) throws Throwable { // 计算一下指令派发时长 StopWatch sw new StopWatch(); sw.start(); Object obj invocation.proceed(); sw.stop(); System.out.println(执行交换机指令工单耗时: [ sw.getTime() ] 毫秒); return obj; } }剩下的我们由于是要异步并行计算得到执行结果于是我们设计一个批处理Hlr任务执行模块HlrBusinessEventTask它要实现java.util.concurrent.Callable接口的方法call它会返回一个异步任务的执行结果。/** * filename:HlrBusinessEventTask.java * * Newland Co. Ltd. All rights reserved. * * Description:Hlr指令派任务执行类 * author tangjie * version 1.0 * */ package newlandframework.batchtask.model; import java.util.concurrent.Callable; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.support.NameMatchMethodPointcutAdvisor; public class HlrBusinessEventTask implements CallableInteger { private NotifyUsers user null; private final static String MAPPERMETHODNAME execute; public HlrBusinessEventTask(NotifyUsers user) { this.user user; } Override public Integer call() throws Exception { synchronized (this) { ProxyFactory weaver new ProxyFactory(new HlrBusinessEvent()); NameMatchMethodPointcutAdvisor advisor new NameMatchMethodPointcutAdvisor(); advisor.setMappedName(MAPPERMETHODNAME); advisor.setAdvice(new HlrBusinessEventAdvisor()); weaver.addAdvisor(advisor); BusinessEvent proxyObject (BusinessEvent) weaver.getProxy(); Integer result new Integer(proxyObject.execute(user.getUserId())); // 返回执行结果 return result; } } }接下来我们要把并行异步加载的查询结果和并行异步处理任务执行的模块给它组合起来使用故重新封装一个通知用户批处理任务管理类模块NotifyUsersBatchTask。它的主要功能是批量并行异步加载查询待停复机的手机用户然后把它放入并行异步处理的线程池中进行异步处理。然后我们打印出本次批处理的任务一共有多少成功数和失败数分别是多少当然本文还给出了另外一种JMX方式的监控。NotifyTaskSuccCounter类主要是统计派发的任务中执行成功的任务的数量而与之相对应的类NotifyTaskFailCounter是用来统计执行失败的任务的数量。具体的代码如下/** * filename:NotifyUsersBatchTask.java * * Newland Co. Ltd. All rights reserved. * * Description:通知用户批处理任务管理类 * author tangjie * version 1.0 * */ package newlandframework.batchtask; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.sql.DataSource; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import org.apache.commons.collections.Closure; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.functors.IfClosure; import org.apache.commons.lang.StringUtils; import newlandframework.batchtask.jmx.BatchTaskMonitor; import newlandframework.batchtask.model.NotifyUsers; import newlandframework.batchtask.parallel.BatchQueryLoader; import newlandframework.batchtask.parallel.BatchTaskReactor; public class NotifyUsersBatchTask { public NotifyUsersBatchTask() { } private ArrayListDataSource dataSource; // 基于JMX的任务完成情况监控计数器 private BatchTaskMonitor monitor new BatchTaskMonitor(BatchTaskReactor.BATCHTASK_THREADPOOL_NAME); // 支持同时加载多个数据源 public NotifyUsersBatchTask(ArrayListDataSource dataSource) { this.dataSource dataSource; } // 批处理任务执行成功计数器 class NotifyTaskSuccCounter implements Closure { public static final String NOTIFYTASKSUCCCOUNTER TASKSUCCCOUNTER; private int numberSucc 0; public void execute(Object input) { monitor.increaseBatchTaskCounter(NOTIFYTASKSUCCCOUNTER); numberSucc; } public int getSuccNumber() { return numberSucc; } } // 批处理任务执行失败计数器 class NotifyTaskFailCounter implements Closure { public static final String NOTIFYTASKFAILCOUNTER TASKFAILCOUNTER; private int numberFail 0; public void execute(Object input) { monitor.increaseBatchTaskCounter(NOTIFYTASKFAILCOUNTER); numberFail; } public int getFailNumber() { return numberFail; } } // 并行加载查询多个水平分库的数据集合 public ListNotifyUsers query() throws SQLException { BatchQueryLoader loader new BatchQueryLoader(); String strSQL select home_city, msisdn, user_id from notify_users; for (int i 0; i dataSource.size(); i) { Connection con dataSource.get(i).getConnection(); Statement st con.createStatement(); loader.attachLoadEnv(strSQL, st, con); } ListResultSet list loader.executeQuery(); System.out.println(查询出记录总数为: list.size()); final ListNotifyUsers listNotifyUsers new ArrayListNotifyUsers(); for (int i 0; i list.size(); i) { ResultSet rs list.get(i); while (rs.next()) { NotifyUsers users new NotifyUsers(); users.setHomeCity(rs.getInt(1)); users.setMsisdn(rs.getInt(2)); users.setUserId(rs.getInt(3)); listNotifyUsers.add(users); } } // 释放连接资源 loader.close(); return listNotifyUsers; } // 批处理数据集合,任务分派 public void batchNotify(ListNotifyUsers list, final ExecutorService excutor) { System.out.println(处理记录总数为: list.size()); System.out.println(StringUtils.center(记录明细如下, 40, -)); NotifyTaskSuccCounter cntSucc new NotifyTaskSuccCounter(); NotifyTaskFailCounter cntFail new NotifyTaskFailCounter(); BatchTaskPredicate predicate new BatchTaskPredicate(excutor); Closure batchAction new IfClosure(predicate, cntSucc, cntFail); CollectionUtils.forAllDo(list, batchAction); System.out.println(批处理一共处理: list.size() 记录,处理成功: cntSucc.getSuccNumber() 条记录,处理失败: cntFail.getFailNumber() 条记录); } }
延伸阅读

更多相关文章

2026/10/4 8:07:49

西安便民社区系统开发哪家靠谱,邻里互助匹配架构教程

西安多数老旧小区、新建社区均存在邻里沟通弱、便民资源闲置、互助需求匹配难的问题,传统社区微信群、线下求助模式信息杂乱、时效性差、无规范记录,无法形成可持续的邻里互助体系。便民社区系统的核心核心模块之一就是邻里互助匹配架构,支持…

2026/10/2 14:16:44

星盘接口开发文档:骰子占卜接口指南

星盘接口开发文档:骰子占卜接口指南 1. 引言 本文档详细介绍了占星系统的骰子占卜接口的使用方法,包括请求参数详解、响应数据结构、错误处理机制以及最佳实践建议。 2. 接口基础信息 接口名称: 骰子占卜 请求方式: POSTContent-Type: application/x-www…

2026/10/4 12:21:37

翻后训练工具实战:把Solver的46%过牌率变成肌肉记忆

1. 这不是理论课,是翻后实战的“肌肉记忆”训练场你有没有过这种体验:河牌圈面对对手的持续下注,手心冒汗,盯着底池和自己的K♠T♠,脑子里飞速闪过“他是不是诈唬?”“我该跟注还是弃牌?”“如果…

2026/10/4 12:21:37

从PDF处理到OCR识别:这40个在线工具让效率翻倍

1. 为什么我坚持用在线工具,以及这套清单的筛选标准先说个实话:我电脑里装了不下五十个所谓的“专业软件”,但真正每天打开率最高的,反而是那些不用安装、打开浏览器就能用的在线工具。PDF要合并、图片要压缩、视频要截个图、JSON…

2026/10/4 12:21:37

Minio Java SDK下载报错:okhttp3 addUnsafeNonAscii异常排查与解决

1. 一次诡异的报错:Minio 下载文件时炸出了 okhttp3 的 addUnsafeNonAscii先说结论:这个报错十有八九不是 Minio 本身的问题,而是 Java 客户端在拼接 HTTP 请求头时,遇到了非 ASCII 字符(比如中文、日文、带重音符号的…

2026/10/4 12:21:37

C# WinForm酒店管理系统源码实战:可部署、可扩展、可交付

简介:这是一套基于C# WinForm与SQL Server开发的酒店管理系统完整源码工程,面向.NET初学者与中小型项目开发者,旨在帮助用户掌握桌面应用开发、数据库设计及业务逻辑分层实现。系统覆盖客房管理、入住登记、费用结算等核心模块,支…

2026/10/4 0:01:02

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/4 0:01:02

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/4 1:01:05

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 0:01:02

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/4 0:01:02

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/4 1:01:05

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑