PE框架源码分析(3): 责任链

总览

请求通过Adapter转换为渠道无关的Context(包含User,Data等)后,将经过责任链的处理,才交给业务逻辑处理。 

基本流程

前端将Context交给coreController,经历了以下处理流程: 
coreController—>Chain—>Template—>Action

Transaction类

对于一个请求,处理流程通常是:首先校验请求,然后交给具体的逻辑单元处理。在PE中,完成这样一个过程称为执行一个交易(Transaction)。

为了更好的抽象与复用,交易的校验部分称为责任链(Chain),将交易的共用逻辑流程抽取为模板(Template),具体的逻辑单元称为动作(Action)。

在PE中,请求路径是没有层级结构的,所有的请求地址都是类似http://xxxxxxxxx/transactionId.do。其中的transactionId就是唯一的交易id。

PE中Transaction中对应的类叫做TransactionConfig,CoreController根据transactionId获取其实例,并执行其责任链。

transactionConfig = (TransactionConfig)transactionConfigs.get(context.getTransactionId());//从ConcurrentHashMap中获取
Chain chain = transactionConfig.getTemplate().getChain();
chain.execute(context, null);

Chain类

链中执行的校验逻辑被抽象为一个个命令(Command)。链维护了一个Command list,执行Chain就是循环迭代执行该命令表:

扫描二维码关注公众号,回复: 2458571 查看本文章
  1. public boolean execute(Context context, Map map)throws PeException{
  2. //...
  3. for(Iterator it = commands.iterator(); it.hasNext();){
  4. Command command = (Command)it.next();
  5. try{
  6. saveResult = command.execute(context, setting);
  7. if(saveResult)
  8. break;
  9. }catch(Exception e){
  10. saveException = e;
  11. break;
  12. }
  13. }
  14. //...
  15. }

Chain可以类比SpringMVC中的Interceptor,通过拦截业务逻辑的执行,完成一些处理。

Command类

表示一个校验命令,基本方法是execute():

  1. public boolean execute(Context context, Map setting)
  2. throws PeException;

delegateCommand

委托命令将执行其模板:

  1. public boolean execute(Context context, Map setting)
  2. throws PeException{
  3. context.getTransactionConfig().getTemplate().execute(context);
  4. return false;
  5. }

Template类

模板是抽取多个交易的共同逻辑流程,这些交易通常使用相同的Chain,执行类似的任务,如查询、提交等。 
不同的模板,调用action的方法不同。通常它们都有一个共同的父类AbstractSequenceTemplate,它定义了基本的处理流程,并预留方法供子类自定义实现来调用action中的方法:

  1. public void execute(final Context context) throws PeException{
  2. final Map actions=getActions();
  3. Action action;
  4. for(Iterator it = actions.keySet().iterator(); it.hasNext(); doInternal(context, action)){
  5. action = getAction((String)it.next(), context);
  6. }
  7. }
  8. protected abstract void doInternal(Context context, Action action)
  9. throws PeException;//预留方法

AbstractSequenceTemplate.execute()将迭代处理所有的action,而具体的处理方法doInternal()由子类去实现。

如:

  1. public class PageLoaderSequenceTemplate extends AbstractSequenceTemplate{
  2. protected void doInternal(Context context, Action action)
  3. throws PeException{
  4. if(action instanceof PageLoader)
  5. ((PageLoader)action).init(context);
  6. }
  7. }

Action类

action为具体的逻辑单元,在后面介绍。

配置信息

Chain

chain包含了command列表,这些command提供校验、拦截的功能。主要包括以下功能:

  • requestCheckCommand UGC(用户提交内容)和谐,防止XSS
  • validationCommand 字段格式校验(长度,类型,正则)
  • ruleCommand 字段规则校验
  • delegateCommand 执行业务逻辑
  • wxSetJsonResultCommand 微信渠道返回结果
  • tokenControlCommand 防重复提交
  • tokenControlVercodeCommand 图形验证码校验
  • loginControlCommand 防撞库
  • phoneTokenControlCommand 短信验证码校验
  • roleControlCommand 权限控制
  1. <chain id="chainForPublic">
  2. <commands>
  3. <ref>requestCheckCommand</ref>
  4. <ref>validationCommand</ref>
  5. <ref>ruleCommand</ref>
  6. <ref>delegateCommand</ref>
  7. <ref>wxSetJsonResultCommand</ref>
  8. </commands>
  9. </chain>

Template

Template(模板)通过实现类确定了如何调用action;确定了chain;action通常以占位符的形式存在,将被Transaction级配置信息覆盖。

  1. <template id="模版Id"
  2. class="Full qualified class name of this Template"
  3. chain="引用的责任链Id">
  4. <actions><!--模版级定义的Actions. -->
  5. <ref name="act01">Placeholder</ref>
  6. </actions>
  7. </template>

Transaction

Transaction的配置信息如下:

  1. <transaction id="交易Id" template="引用的模版Id">
  2. <actions>
  3. <ref name="act01" >交易级定义的Action</ref>
  4. </actions>
  5. <fields>
  6. <field name="域名1">Style名称</field>
  7. ...
  8. <field-list name="域名x" counter="域名y">
  9. <fields>
  10. <field name="域名n"> Style名称</field>
  11. <field-list>...</field-list>
  12. </fields>
  13. <field-list>
  14. </fields>
  15. <rules>
  16. <rule id="equals">
  17. <param name="content">dataMap.Password == dataMap.ConfirmPassword</param>
  18. <param name="messageKey">validation.password.equal</param>
  19. </rule>
  20. </rules>
  21. <channels>
  22. <channel type="http">
  23. <param name="success">页面名称</param>
  24. <param name="successN">页面名称</param>
  25. <param name=”success5”>OperatorWelcome</param>
  26. </channel>
  27. </channels>
  28. </transaction>

其确定了:

  • action transaction的actions将覆盖(template)的actions属性。transaction的配置信息确定了具体的action。
  • fields 确定了要将style校验(正则匹配)和传递给action的字段;
  • rules 定义了逻辑判断规则,支持OGNL表达式。由于比较鸡肋,很少使用;
  • channels 定义了不同请求来源的可选视图。在action中通过返回定义的name,如success,来返回视图名。

总结

责任链主要用于提供XML配置式安全保护的安全性框架,同类的开源方案有Spring Security。责任链提供的功能主要包括:字段校验、用户登录校验、权限校验、手机验证码、密码校验等。责任链是一种成熟的设计模式,通过配置实现了功能复用,思想上没什么问题。

但class与bean之间的两种抽象,以及class的继承关系与bean的继承关系这两种继承关系可能会让人感到困惑。

个人看来,注解相比xml的配置信息更加灵活,同时也具有可配置的优点,更值得使用。

猜你喜欢

转载自www.cnblogs.com/liwanxing/p/9389590.html
今日推荐