PE框架源码分析:业务流
Posted liwanxing
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PE框架源码分析:业务流相关的知识,希望对你有一定的参考价值。
总览
责任链的终点是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调用的逻辑:
- 将dataMap中的密码经过加密并替换,这些字段是可配置的
- 将dataMap格式化填充到XML模板中
- 发起TCP请求,将XML报文发往目标IP,并返回接受XML报文
- 解析XML报文,获取响应dataMap
而Service端的逻辑是:
- 开启TcpServer,并监听指定端口
- 接受XML报文
- 解析报文,调用目标主机交易
- 将返回dataMap格式化填充到XML模板中
- 通过TCP返回响应XML报文
总结
构建了一个业务流框架,除了静态资源请求,PE框架中的其它请求只能以交易的形式存在,从url上来讲就是http://www.xxx.com/xxxx.do
。请求分为两种:query和twophase,开发人员似乎只需要复制配置信息、修改命名、修改业务逻辑就可以完成开发,但这样导致代码质量很差,一个方法写到底,适合简单的功能。对于网银这样的开发足够,但对于复杂功能的开发,这种灵活性不足的模式并不适合。
以上是关于PE框架源码分析:业务流的主要内容,如果未能解决你的问题,请参考以下文章
Android 插件化VirtualApp 源码分析 ( 目前的 API 现状 | 安装应用源码分析 | 安装按钮执行的操作 | 返回到 HomeActivity 执行的操作 )(代码片段
Android 逆向整体加固脱壳 ( DEX 优化流程分析 | DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析 | /bin/dexopt 源码分析 )(代码片段