12.2. OperaMasks请求处理生命周期

正如Servlet在容器管理下需要经历一定的生命阶段,OperaMasks在整个生命周期的过程中也分为6个阶段, 其他 Web 框架也都具有类似的生命周期,只不过它们没有进行很好的宣传。

  1. 恢复视图阶段(Restore View Phase)

  2. 应用请求值阶段(Apply Request Value Phase)

  3. 处理验证阶段(Process Validations Phase)

  4. 更新模型值阶段(Update Model Value Phase)

  5. 调用应用程序阶段(Invoke Application Phase)

  6. 渲染响应阶段(Render Response Phase)

虽然这个清单中列出了OperaMasks处理用户请求时的每个阶段。但OperaMasks的生命周期很难是一成不变的,有些情况下可以跳过某个阶段或者合并多个阶段。

首次请求时,只执行恢复视图阶段与渲染响应阶段,postback时原则上(没有转换和校验错误,用户代码没有显式改变执行流程)会顺序执行全部六个阶段。若在处理验证阶段或更新模型值阶段出现转换或校验错误,都会导致流程在本阶段执行完毕后(注意不是立即)直接跳转到渲染响应阶段。用户应用代码也可以在任一阶段中通知引擎跳过某些阶段,使用以下方法:

FacesContext.getCurrentInstance().renderResponse() 
本阶段执行完毕后直接跳到渲染响应阶段

FacesContext.getCurrentInstance().responseComplete()
本阶段执行完毕后直接终止当前生命周期

尽管如此,OperaMasks的这六个阶段的逻辑是非常好和值得遵循的。OperaMasks请求处理生命周期流程如下图:

OperaMasks生命周期图

图 12.3. OperaMasks生命周期图


下面我们逐一看看每个生命周期的职能。

12.2.1. 恢复视图阶段(PhaseId.RESTORE_VIEW)

在生命周期的第一个阶段做的首件事情就是从FacesContext中获得ViewHandler,并调用ViewHandler的initView()方法,这个方法主要为了设置请求的编码类型。OperaMasks接着会判断当前请求是否首次请求而执行不同操作。假如是首次请求,则从请求的物理页面中创建一个空视图并把它保存到FacesContext的viewRoot属性中。

而这个viewRoot就是通常我们所说的构件树的根节点。再接下来OperaMasks就会直接从第一阶段跳到第六阶段即渲染响应阶段执行。假如不是首次请求(用户访问之前访问过的页面),这种情况下包含页面的视图早已经存在了,它可能保存在客户端或者服务器端,OperaMasks会根据viewId从FacesContext中恢复上一次响应时的构件树模型,该构件树包含了当前请求页面下的所有构件状态。接着就进入应用请求值阶段了。

恢复视图阶段

图 12.4. 恢复视图阶段


12.2.2. 应用请求值阶段(PhaseId.APPLY_REQUEST_VALUES)

由于上一阶段恢复的只是上一次响应时的构件树模型,所以OperaMasks需要根据本次请求中的值来对构件树进行状态更新。此阶段的意图就是给构件树中的各个构件提供一个机会来根据当前request中的信息(parameter, header, cookie等等)更新自身的状态。它的原理说起来也不复杂,从FacesContext中获取viewRoot,调用它的processDecodes()方法。这个方法会引发viewRoot下面所有构件的processDecodes()被遍历调用。在这个过程中,不同类型的构件会执行不同的动作,例如 对于UIInput构件,经processDecodes()方法解码后的的值会先使用setSubmittedValue()保存起来,而不进行转换动作,其类型通常(但不强制)是String类型。 继承了EditableValueHolder的构件(例如UIInput),若其immediate属性被设为真,则其转换与校验动作将在本阶段进行(包括可能激活ValueChangeEvent事件)。 继承了ActionSource的构件(例如UICommand)若得知自己被激活了,会向事件队列中加入一个ActionEvent。如果这个构件的immediate属性为真,这个事件将在本阶段结束时被分发,否则这个事件将在Invoke Application阶段结束时被分发。 值得注意的是,如果某个构件的值转换或值的有效性验证失败了,就会生成一个错误消息,并在 FacesContext 中进行排队,在产生响应的阶段会显示其中的消息,同时还会显示所有的验证错误。用户也可以调用FacesContext.addMessage()方法来加入提示消息。

12.2.3. 处理校验阶段(PhaseId.PROCESS_VALIDATIONS)

除了在上一阶段进行过校验的构件之外,剩下的校验都会发生在这个阶段。类似的,这个阶段的原理也是从FacesContext中获取viewRoot,然后调用它的processValidators()方法。每个构件在执行有效性校验的过程中都会依据一定的规则,这些规则有些是OperaMasks预先定义的,也有些是用户自己定义的。同样,如果某个构件的值有效性校验失败了,OperaMasks会调用FacesContext.addMessage()方法来加入错误提示消息。然后把这个构件设为无效,最后调用FacesContext实例的renderResponse()方法让流程直接跳去执行渲染响应阶段。 若此阶段顺利执行则说明视图中所有构件都成功通过了值转换和有效性校验,为下个阶段(更新模型值阶段)提供了有效性保证。

12.2.4. 更新模型值阶段(PhaseId.UPDATE_MODEL_VALUES)

若处理流程顺利到达本阶段,则可以认为当前request中的信息在语法与语义(由之前执行的校验动作定义)上均合法,构件树中各个构件的本地值(local value)均已更新。本阶段的目的是更新应用中的模型数据信息,为执行应用的事件(例如与业务相关的事件)作好准备。这里所说的模型指的是与页面绑定的后台bean(或称为管理bean),而更新模型值主要是更新与页面构件值绑定的bean的属性。它的原理同样是调用viewRoot的processUpdates ()方法然后遍历至视图的每个构件。

12.2.5. 调用应用程序阶段(PhaseId.INVOKE_APPLICATION)

如果说前面4个阶段都是OperaMasks为了保证能准确无误、顺利的执行应用相关的业务逻辑的话,那么这个阶段则是真正让用户大显身手的地方了。通常会在这个阶段对页面提交的表单进行处理,例如一个注册页面提交后可以在这个阶段对提交的信息进行持久化,然后还可以利用OperaMasks 的导航跳转至一个特定的页面。

12.2.6. 渲染响应阶段(PhaseId.RENDER_RESPONSE)

在此阶段,OperaMasks引擎使用配置指定的渲染包(Render-Kit)将构件树渲染为输出格式。通过选用不同的Render-Kit,这个输出格式可以有很多形式,例如静态HTML页面、带AJAX支持的HTML页面、xml,甚至是flash等等。目前OperaMasks主要的输出格式是带AJAX支持的HTML页面。

实现原理主要是从Application实例中获取ViewHandler实例,并调用其renderView()进行渲染方法。本阶段的主要逻辑事实上在ViewHandler子类的renderView()实现中。目前大部分OperaMasks应用主要使用FaceletViewHandlerHook来进行处理。