1. 引言
在金融交易系统中,联机交易处理器的设计直接关系到系统的稳定性、并发能力和可维护性。本文以 OnlineRichHandler 为例,深入解析一个基于 Spring 框架的联机交易处理器的核心实现,涵盖服务入口、前置校验、交易锁机制、幂等处理等关键环节。
2. 类结构与依赖注入
OnlineRichHandler 实现了 InitializingBean 和 ApplicationContextAware 两个接口,前者用于在 Bean 初始化完成后加载交易服务映射,后者用于获取 Spring 容器上下文。类中通过 @Resource 注入了三个核心依赖:
- OnlineApplyRecMapper:申请记录数据访问层,用于保存交易申请信息。
- RichIdGenerator:交易 ID 生成器,为每笔交易生成唯一流水主键。
- RedisService:Redis 服务封装,提供分布式锁和缓存能力。
此外,类内部维护了一个 onlineServiceAnnotationInfoMap 映射表,用于根据交易码快速定位对应的交易处理配置。
3. 服务入口 invoke 方法
invoke 方法是整个处理器的入口,接收请求参数 Map 和响应参数 Map。方法内部按照以下流程执行:
- 启动 Stopwatch 计时器,记录交易处理耗时。
- 初始化响应 Map,设置默认的成功响应码。
- 执行前置校验,校验失败则直接返回。
- 构建 OnlineHelper 对象,封装交易上下文信息。
- 尝试获取 Redis 分布式交易锁,防止同一笔交易被并发处理。
- 获取锁成功后调用 handleTransaction 执行实际交易逻辑。
- 在 finally 块中释放交易锁,确保锁资源不泄漏。
核心代码如下:
java
public void invoke(Map<String, Object> requestMap, Map<String, Object> responseMap) {
Stopwatch started = Stopwatch.createStarted();
LOGGER.info("联机RICH处理器开始执行处理,请求参数:{}", requestMap);
initResponseMap(responseMap);
if (!validateRequest(requestMap, responseMap)) {
return;
}
OnlineHelper onlineHelper = onlineHelper(requestMap);
boolean tryLock = false;
try {
tryLock = redisService.lock(onlineHelper.getTransLockKey(), onlineHelper.getTradeId(), onlineHelper.getTransTimeOut());
if (!tryLock) {
responseMap.put(TransactionConstant.TRADE_FLAG, TransactionConstant.TRADE_FLAG_N);
responseMap.put(TransactionConstant.TRADE_MSG, "联机系统正在处理该笔交易,请稍后");
return;
}
handleTransaction(requestMap, responseMap, onlineHelper);
} catch (Exception e) {
LOGGER.error("交易处理过程中系统异常", e);
} finally {
if (tryLock) {
redisService.unlock(onlineHelper.getTransLockKey(), onlineHelper.getTradeId());
}
}
LOGGER.info(CommonUtils.defVal(requestMap, TransactionConstant.REQ_SERI_NO) + "交易时长==>:" + started.elapsed(TimeUnit.MILLISECONDS));
}
4. 前置校验与响应初始化
initResponseMap 方法负责初始化响应 Map,默认将响应码设置为成功状态,响应消息设置为空字符串。这样在后续处理中,即使某个环节失败,也能保证响应 Map 中始终存在基础字段。
java
private void initResponseMap(Map<String, Object> responseMap) {
responseMap.put(TransactionConstant.RESP_CODE, TransactionConstant.RESP_CODE_SECC);
responseMap.put(TransactionConstant.RESP_MESG, "");
}
5. OnlineHelper 构建
onlineHelper 方法负责构建交易上下文对象 OnlineHelper,其中包含交易 ID、系统标识、流水号、交易锁 Key、超时时间等关键信息。交易锁 Key 由系统标识、流水号和系统编码拼接而成,确保锁的粒度精确到单笔交易。
java
private OnlineHelper onlineHelper(Map<String, Object> requestMap) {
OnlineHelper onlineHelper = new OnlineHelper();
return onlineHelper.setTradeId(richIdGenerator.nextIdStr())
.setSysCode(CommonUtils.defVal(requestMap, TransactionConstant.REQ_SYS_CODE))
.setSeriNo(CommonUtils.defVal(requestMap, TransactionConstant.REQ_SERI_NO))
.setTransLockKey(RedisConstant.SYS.concat(onlineHelper.getSeriNo()).concat(":").concat(onlineHelper.getSysCode()))
.setTransTimeOut(RedisConstant.TRANS_TIME_OUT)
.setStopwatch(Stopwatch.createStarted());
}
6. 交易处理核心逻辑
handleTransaction 方法是交易处理的核心,主要完成以下工作:
- 从请求 Map 中提取交易码和流水号。
- 根据交易码从映射表中获取对应的注解配置信息。
- 若配置不存在,则返回交易不存在的错误提示。
- 若交易配置允许记录日志,则先执行幂等校验,防止重复提交。
- 幂等校验通过后,保存申请信息到数据库。
- 初始化交易日期,并根据锁类型决定是否加锁处理。
核心代码如下:
java
private boolean handleTransaction(Map<String, Object> requestMap, Map<String, Object> responseMap, OnlineHelper helper) throws Exception {
String tranCode = (String) requestMap.get(TransactionConstant.REQ_TRAN_CODE);
String seriNo = (String) requestMap.get(TransactionConstant.REQ_SERI_NO);
requestMap.put(TransactionConstant.TRAN_INST_ID, helper.getTradeId());
OnlineServiceAnnotationInfo onlineServiceAnnotationInfo = onlineServiceAnnotationInfoMap.get(tranCode);
if (onlineServiceAnnotationInfo == null) {
responseMap.put(TransactionConstant.TRADE_FLAG, TransactionConstant.TRADE_FLAG_N);
responseMap.put(TransactionConstant.TRADE_MSG, "该交易不存在,tradeCode=" + tranCode);
return false;
}
if (onlineServiceAnnotationInfo.isLogRecord()) {
if (checkResubmit(requestMap, responseMap)) {
LOGGER.info("流水号为[{}],系统标识为[{}], 已经处理完成,直接返回", helper.getSeriNo(), helper.getSysCode());
return true;
}
}
if (onlineServiceAnnotationInfo.isLogRecord()) {
saveRequestData(helper, requestMap);
}
requestMap.put(TransactionConstant.ACCT_TRAN_DATE, AcctTranDateUtil.getTrandate());
OnlineServiceLockType lockType = onlineServiceAnnotationInfo.getOnlineServiceLockType();
if (lockType == null || OnlineServiceLockType.NONE == lockType) {
// 无锁直接放行
}
return true;
}
7. 总结
OnlineRichHandler 通过合理的分层设计和分布式锁机制,实现了高并发场景下联机交易的可靠处理。其核心设计思路包括:通过注解配置驱动交易分发、通过 Redis 分布式锁保证交易幂等、通过 Stopwatch 实现耗时监控。这种设计模式在金融交易系统中具有较高的参考价值。