PE框架源码分析(5):业务流

总览

责任链的终点是Template,其实现类确定了actions被调用的具体方法,决定了Transaction的流程逻辑。从Transaction着手,主要分为2种:

  • query 查询数据交易,负责查询类的请求
  • twophase 业务提交交易,负责需要提交的请求。这里又分3步:pre(提供初始页面),confirm(提供确认页面),submit(提供结果页面)

这是一个业务流风格,通过父类和接口限定了实现类向框架暴露的被调用逻辑。

分析

query

query transaction(查询类交易)的模板常用的是publicQueryTemplate,它的实现类会调用action的execute()方法:

protected void doInternal(Context context, Action action){
...
if(action instanceof Executable)
((Executable)action).execute(context);
...
}

twophase

twophase transaction(两步验证类交易)区分为3步,是因为提交这样流程的固有页面逻辑:

  • pre页面 用户填入要提交的信息
  • confirm页面 对上一页面信息的重复展示,用户需对信息确认
  • result页面 展示结果

因此对应的就有3个交易负责一个数据提交流程。

pre transaction(准备交易)的模板常用的是publicSequenceTemplate,它的实现类会调用action的execute()方法。

confirm transaction(确认交易)的模板常用的是trsConfirmTemplateWPC,它的实现类会调用action的prepare()方法,该方法一般会对数据进行校验工作。

protected void doInternal(Context context, Action action){
...
if (action instanceof Preparable)
((Preparable) action).prepare(context);
...
}

submit transaction(提交交易)的模板常用的是twoPhaseTrsTemplateForTC,它会依次调用action的prepare(),submit()方法。prepare()通常用于数据校验,submit()会做数据提交工作。通常与cofirm transaction共享同一个action。

protected void doInternal(Context context, Action action){
...
if(action instanceof Preparable)
((Preparable)action).prepare(context);
...
((Submitable)action).submit(context);
...
}

前后端分离

为了将业务逻辑放到后端中去(mca),并独立部署,pe框架将action中的业务逻辑抽取到后端成为service。后端就变成了MCXXXXXQueryService,MCXXXXXSubmissionService,它们的方法也相应存在execute(),prepare(),submit()方法。前端的action通过配置好的映射去调用对应的方法。这是一种RPC实现,不论这种方式的好坏,我们关注的是其如何实现的。

分析

在resolver.xml中定义了映射信息,如下:

<bean id="hostTrsCodeResolver" class="com.csii.ibs.action.HostTrsCodeResolver">
<map name="map">
<param name="BFinSign">epay.BFinSign</param>
<!--<param name="交易Id">主机交易Id</param>-->
...
</bean>

所有action bean都继承了以下action,它们的实现类也存在继承关系:

<action id="BaseQueryAction" class="com.csii.ibs.action.IbsQueryAction">
<ref name="trsCodeResolver">hostTrsCodeResolver</ref>
<ref name="returnCodeValidator">hostReturnCodeValidator</ref>
<ref name="transportBean">TransformerTransport</ref>
<param name="idFactoryName"></param>
<ref name="sqlMap">ibsdbSqlMapExecutor</ref>
</action>
<action id="BaseTwoPhaseAction" class="com.csii.ibs.action.IbsTwoPhaseAction">
<ref name="trsCodeResolver">hostTrsCodeResolver</ref>
<ref name="returnCodeValidator">hostReturnCodeValidator</ref>
<ref name="transportBean">TransformerTransport</ref>
<ref name="transactionTemplate">ibsdbTxTemplate</ref>
<ref name="sqlMap">ibsdbSqlMapExecutor</ref>
</action>

Ibs表示发起主机交易,这两个action的实现类都继承了AbstractIbsAction类,该类的issueHostTrs()方法将发起PRC调用。在编写业务Action的时候,通过super.xxx()将调用父类的issueHostTrs()方法发起主机交易:

public void execute(Context context) throws PeException {
/* 业务逻辑... */
//发起主机交易
super.execute(context);
/* 业务逻辑... */
}

AbstractIbsAction的issueHostTrs()方法如下:

public Object issueHostTrs(Context context, Map map)
throws PeException{
...
//构造请求数据
Map map = context.getDataMap();
map.put("_TransName", context.getTransactionId());//交易id
map.put("_JnlNo", idFactory.generate());//流水
map.put("_TransactionTimestamp",context.getTimestamp());//时间
map.put("_HostTransactionCode", trsCodeResolver.resolve(context));//主机交易id
...
//发起RPC调用
Transport transport = getHostTransport();
fromHost = transport.submit(map);
...
}

由transport对象完成RPC调用,transport将在后续章节分析,这里讲述一下Client端的RPC调用的逻辑:

  1. 将dataMap中的密码经过加密并替换,这些字段是可配置的
  2. 将dataMap格式化填充到XML模板中
  3. 发起TCP请求,将XML报文发往目标IP,并返回接受XML报文
  4. 解析XML报文,获取响应dataMap

而Service端的逻辑是:

  1. 开启TcpServer,并监听指定端口
  2. 接受XML报文
  3. 解析报文,调用目标主机交易
  4. 将返回dataMap格式化填充到XML模板中
  5. 通过TCP返回响应XML报文

总结

构建了一个业务流框架,除了静态资源请求,PE框架中的其它请求只能以交易的形式存在,从url上来讲就是http://www.xxx.com/xxxx.do。请求分为两种:query和twophase,开发人员似乎只需要复制配置信息、修改命名、修改业务逻辑就可以完成开发,但这样导致代码质量很差,一个方法写到底,适合简单的功能。对于网银这样的开发足够,但对于复杂功能的开发,这种灵活性不足的模式并不适合。

猜你喜欢

转载自www.cnblogs.com/liwanxing/p/9389796.html