Fight With Me!!!

导航

前端控制器

原文地址: http://www.cnblogs.com/firstdream/archive/2012/02/09/2344160.html


前端控制器一


4年以前,当我还在一种叫ASP的东西上工作的时候,我整天为两个问题头疼不已:一是如何将分散的页面控制整合起来。解释型的服务器端脚本,每个页面都有 接收和处理请求的能力。这样以每个页面作为独立的单元来处理请求让人感觉粒度太小,分散又不爽。二是如何减少重复代码。脚本语言里处理重复代码的灵丹妙药 是include。每个页面里都可以include header,footer,session checker,屡试不爽。但有一次我很不幸,我要改一下header的名字……
后来投靠了java,用了struts,豁然开朗,就像天空中飘下来几个大字:前端控制器。在这几个字的怀里缠绵已久,回望脚本语言林林总总,处处鲜花烂漫。

前端控制器在《J2EE核心模式》一书中已经完整的定义过了了,不再复述。下面只是记一下自己在工作中遇到过的前端控制器模式的实例:
1. 解释型脚本的前端控制器的实现:近期接触了一个php项目,打开看了它的index.php,顿时感觉醍醐灌 顶,赞叹作者思想精妙不已,一个小小的页面里面做了控制分发和页面Layout处理。用户所有的请求都发送给index.php页面,然后后面加上几个参 数,如action和event。该系统个php文件的关系是通过命名约束来处理的。比如如果action=XXX,那么会有一个 XXX.class.php,一个XXX.page.template.php,还有相关的footer,header,form,content之类的 页面对应文件。当index页面接到请求的时候通过action名字匹配,利用万能的include将对应的class.php加载进来,作为对 action进行处理的command使用。当command处理完以后,然后再把对应的 page.template,footer,header,content加载进来,然后根据event进行处理。所有动作完成后,把组装好的页面返回给 用户。一次控制分发和页面处理就完成了。一个百行的index.php代码就完成了一个完整的前端控制器,整个框架不可谓不轻啊。脚本的灵活性让我这个整 天活在java的xml配置文件里的人好生羡慕啊。
更加完整的解释型前端控制器:用过一个月的ColdFusion,解释型的标签式语言。March II是这个平台上最流行的MVC框架之一。这个框架和struts非常相似,一个配置核心的XML文件。不过解释型脚本的问题在于它们的最小粒度永远都是 独立的一个页面。这个框架接收用户请求的还是那个index.cfm文件。这个文件会将请求转给March II的核心文件,并且在第一次被调用的时候会初始化一个应用级的变量,来保存系统xml里的信息。然后通过index.cfm后面的参数匹配来处理 action(MarchII叫它listener),event之类的东西。这个系统在实现信息包装、控制分发和页面处理的同时,还实现了拦截器的功 能。在处理action的listener前面加了一个叫filter的东西来处理,来进行过滤用户信息。整体来说这个框架算是一个比较完整的MVC框 架。也是我见过的比较完整的解释型脚本的框架。

2.JAVA EE里的前端控制器:Strut1和Struts2里面的做法算是比较经典的两种前端控制器。由于 JAVA EE中对处理用户请求的单元进行了重新定义,类型更丰富,比如Filter和Servlet。而配置的映射机制使接收用户请求的粒度变得很有弹性。 struts1里面使用Servlet作为前端控制器,来实现用户请求的封装,控制分发,和结果返回处理。struts2 对struts1这方面最大的改进莫过于使用Filter来作为前端控制器。由于Filter本身就是非常典型的Chain模式,请求运转与Filter 之中,就是行走于一个链中,而且filter接收和处理请求位于比Servlet更靠前的位置,这使我们在基于它进行开发时,活动余地更大,更增强了我们 对request和response的控制,也提供了一种框架内更便捷的拦截器(或者叫子链)实现方式。关于Struts1和struts2,想必大家都 已经烂熟于心了,也没必要重复了。

3. 令人眼前一亮的奇妙想法:和同事交流前端控制器模式的心得,他说了一个让人神清气爽的例子,也是php的。他维 护的那个项目有一个要求比较安全的模块。刚开始他始终找不到驱动这个模块的核心在哪里。用户请求的地址总是找不到相匹配的php文件,也没有找到代码里有 能处理这些请求分发的地方。找来找去,突然发现这个系统的前端控制器是一个大家天天都会见的页面:HTTP 404错误页面。 因为每一个找不到对应资源的请求都会来到这里,所以他们在这里做了请求解析、控制分发的处理。看到如此巧妙的东西,实在是惊叹设计人员的脑子。且不说这种 做法的好与坏,它至少将核心处理的代码隐藏到了一个应用级别以外的地方。大家大笑以后,想想这也是个很好的trick啊。

 


前端控制器二


 

 表现层的请求处理机制需要支持每个用户多个请求,我们可以以集中式或分散式的方式管理这些请求。 如果以分散的方式进行管理可能会导致如下的一些问题: 每个请求都有一个共同的操作,分散处理可能会导致代码的重复。可能会导致视图导航和视图内容的耦合。分散处..

 

表现层的请求处理机制需要支持每个用户多个请求,我们可以以集中式或分散式的方式管理这些请求。

如果以分散的方式进行管理可能会导致如下的一些问题:

  • 每个请求都有一个共同的操作,分散处理可能会导致代码的重复。
  • 可能会导致视图导航和视图内容的耦合。
  • 分散处理可能会带来更高的维护成本。

如果我们采用集中的方式进行管理,则可以对安全认证、国际化等操作统一处理,同时也可以在一个集中点处理站点的某些操作(如日志记录,站点全局访问控制等),
并且可以在一个地方处理逻辑在多个视图中重复显示。如此我们有了选择前端控制器的理由。

前端控制器建议集中处理所有请求的处理,然而它并没有限制系统中请求处理器的个数,对于不同的服务,完全可以提供不同的处理器。

这与集中式的管理并不矛盾,其实集中只是一种相对的集中,从而达到解决分散式所产生的问题的目的,
任何一种模式只是为解决一些应用场景的特定问题。

运行机制

一个前端控制器其本体包括两部分:一个分发中心(或叫调度处理程序)和一个command(或动作)层次结构。

当一个请求到达服务器,前端控制器接收此请求,从其请求信息中获取足够的内容并决定下一步操作,然后委托给某个command,执行操作。

分发中心可以是一个类或几个类,它没有页面输出,它的作用就是决定最终运行哪一个command。
这里简单点,可以直接根据参数约定,动态识别并执行。

这种简单方法做到了开闭原则,可以在不修改分发中心的前提下添加新的command。

例子

前端控制器在PHP的框架中基本上都会出现,在实现方式上,前端控制器大多采用Apache的url_rewrite模块,

以在.htaccess中重写规则,将所有请求都转发到index.php文件处理。

如PHP的YII框架,Application即YII framework的前端处理器,它是整个请求过程的运行环境。
Application 接收用户的请求并把它分发到合适的控制器作进一步处理。
其一个访问到动作被执行,简单过程如下:

  • 用户访问 Web 服务器,假设其访问地址为index.php?r=post/show,则其入口脚本 index.php 会处理该请求。
  • index.php建立一个应用实例并运行(run方法,在运行前有若干组件加载,初始化操作)。
  • 在应用从一个叫 HTTPRequest 的应用组件获取此次请求的详情。
  • 在urlManager 的组件的帮助下,根据前面获取的请求详情确定用户要请求的控制器和动作,分别对应CController和CInlineAction。
  • 应用建立一个被请求的控制器实例来进一步处理用户请求,控制器确定由它的actionShow 方法来处理 show 动作。
  • 然后它创建并运行和该动作相关的过滤器(CController->runActionWithFilters( )),如果过滤器允许的话,动作被执行,即CController->runAction() ==> CInlineAction->run()。

对于前端控制器,Java体系中的Struts框架以XML配置方式体现,在strut.xml配置动作,在web.xml中配置过滤器。

  • 前端页面提交以“.do”结尾的请求。
  • FilterDispatcher接收请求并调用Action处理该请求。
  • Action处理完毕返回一个逻辑视图。
  • FilterDispatcher根据Action返回逻辑视图创建物理视图
  • 将物理视图返回给页面。

当然我们也可以在一个PHP文件中实现整个前端控制,直接约定命名规范,根据传递进来的参数动态加载处理器,处理方法,视图等。

posted on 2015-03-31 23:25  nickTimer  阅读(571)  评论(0编辑  收藏  举报