1. 恢复视图
在请求处理生命周期的恢复试图阶段,任何JSF的实现都必须执行下面的任务:
l 调用ViewHandler中的initView()方法。在这个方法中为请求设置相应的字符编码
l 检查当前请求中的FacesContext实例。如果FacesContext中已经包含了一个UIViewRoot对象,则:
n 从ExternalContext获得RequestLocale的值,并赋给UIViewRoot的locale属性。
n 检查组件树中的每一个组件,如果组件中的”binding” 已经有ValueExpression,那就调用该ValueExpression的setValue() 方法。
l 根据如下算法判断该请求是回传的还是初始请求:通过调用Application ViewHandler的calculateRenderkitId()找到当前请求render-kit-id,然后再得到这个RenderKit的ResponseStateManager对象,调用isPostBack()方法。
l 对于初始化请求,必须调用FacesContext.renderResponse方法,以便可以跳过其他生命周期阶段,直接进入渲染响应阶段
l 对于回传请求,则调用ViewHandler.restoreView()方法,并返回一个UIViewRoot的对象。 如果返回的UIViewRoot对象为空,则抛出ViewExpireException。然后再重新为其创建一个组件树。
在这个阶段的结束时,FacesContext实例的viewRoot属性要么是从之前响应重新组装,要么是由ViewHandler.createView()方法创建一个新的view。
这个阶段的实现一定不能根据servlet mapping 去取得一个新的View识别符。言下之意就是说:要么创建一个新的view,要么从以前的响应中重组一个View。(自己说)
MyFaces:
Myfaces的实现中,当组件树渲染完成后,会将组件树进行编码,存放在一个叫” jsf_tree_64”的隐藏字段传回前台。当回传时,在恢复视图阶段,根据这个字段来重装组件树。
2. 应用请求值
应用请求值阶段的目的是:根据当前请求中(参数值,请求头,cookies等)的值,更新组件树中每一个组件的当前状态。
在应用请求值的阶段, JSF的实现必须调用组件树中的UIViewRoot的processDecodes()方法,而这个方法也将会递归地调用组件树中所有组件的processDecodes()。而对于UIInput组件,这个时候还可能需要进行数据转换和验证。
在此阶段,某些组件还有一些特殊的行为:
如果该组件的属性immediate = true, 那么该事件将会在应用请求值阶段结束的时候被调用; 否之,该事件将在调用应用程序阶段结束的时候才被调用。
在这个阶段结束的时候,组件树里面所有实现EditableValueHolder的组件都将会更新为新的提交值, 如果这些组件设置immediate = true,那么数据转换跟验证也会执行。如果数据转换或者验证出错,将会调用FacesContext的addMessage()方法。
不管是被调用的任何decode()方法,还是执行事件队列里面的任何监听者,只要有调用到FacesContext中的responseComplete()方法,那么将会清空余下的所有事件,并且结束生命周期; 而同样是上面的所有方法中,如果有人调用了FacesContext中的renderResponse()方法,则同样会清空余下的所有事件,并跳转到渲染响应阶段。
MyFaces:
MyFaces的实现中,在每个组件的decode()方法中,首先是获取该组件对应的Renderer,再调用该Renderer的decode()方法。
如果一个组件有注册了响应的事件,那么在这个阶段就会创建并初始化响应的事件属性。
3. 执行验证
在执行验证的阶段中,JSF的实现必须调用UIViewRoot的processValidators()方法。同样,这个方法将会递归调用所有组件的processValidator方法。需要注意的是,那些实现EditableValueHolder接口,并且设置immediate=true的组件已经在 应用请求值阶段执行了数据转换和验证工作,这里不用再做。
当这个阶段结束时,所有的转换和配置的验证工作都将完成。
不管是被调用的任何validate()方法,还是执行事件队列里面的任何监听者,只要有调用到FacesContext中的responseComplete()方法,那么将会清空余下的所有事件,并且结束生命周期; 而同样是上面的所有方法中,如果有人调用了FacesContext中的renderResponse()方法,则同样会清空余下的所有事件,并跳转到渲染响应阶段。正常的话将进入更新模型值阶段。
MyFaces:
Myfaces中,还是通过组件对应的Renderer来进行,调用getConvertValue的方法进行转换。如果没有指定的Renderer,则默认转换成String。
4. 更新模型值
如果一个请求能够走到这,说明该请求从语义上、语法上是合法的,每个组件也都更新到请求值。这时也就该去更新对应的模型值,为执行队列里的应用程序事件做准备。
在更新模型值阶段,JSF的实现必须调用UIViewRoot的processUpdate()方法,老规则,这将递归调用组件树里面所有的processUpdate()方法。一般来说,都是有组件的updateModel()方法来完成的。
MyFaces1.1.4里面的UIInput的updateModel大致如下:
public void updateModel(FacesContext context)
{
if (!isValid()) return;
if (!isLocalValueSet()) return;
ValueBinding vb = getValueBinding("value");
if (vb == null) return;
try
{
vb.setValue(context, getLocalValue());
setValue(null);
setLocalValueSet(false);
}
}
在这个阶段结束的时候,所有适当的模型数据对象将会跟对应的组件对接上,而该组件上的值也将被清空。
不管是被调用的任何updateModel()方法,还是执行事件队列里面的任何监听者,只要有调用到FacesContext中的responseComplete()方法,那么将会清空余下的所有事件,并且结束生命周期; 而同样是上面的所有方法中,如果有人调用了FacesContext中的renderResponse()方法,则同样会清空余下的所有事件,并跳转到渲染响应阶段。正常的话将进入更新模型值阶段。
MyFaces:
Myfaces在这个阶段的实现是:获取或者创建对应的ValueBinding,然后赋值,清空组件上的Local Value
5. 调用应用程序
JSF的实现必须确保UIViewRoot的processApplication()被调用。processApplication的默认行为是广播给那些指明阶段标识符为PhaseId.INVOKE_APPLICATION的事件。
一些高级的应用程序,或者说应用框架一般会通过调用setActionListner方法来取代默认的ActionListerner。不管怎样,JSF的实现都必须提供一个默认的ActionListerner
MyFaces:
Myfaces的实现中,首先是广播给所有在应用请求值阶段注册的事件。而在这些事件中,包含了对应的UIComponent,然后这些UIComponent再广播给所有的监听者。如果该组件是UICommand的话,还会调NavigationHandler进行导航。如果找到对应的NavigationRule,则重新创建一个UIViewRoot,并赋给FacesContext实例。
6. 渲染响应
这个阶段要完成两件事:
把这两件事绑定到这个阶段的理由是:在一个JSP的应用中,渲染响应就需要创建view,而我们需要在view创建之后才能够保存状态,并且我们不得不在发送响应给用户之前把状态也保存到客户端去。
JSF规范为JSF的实现提供了很多中创建响应内容的方式,包括:
由于实现的方式很多,所以也不明确指出实现的机制应该怎样。但是,所有JSF的实现在这个阶段都必须实现下面的需求:
在渲染接近完成时,view 的完成状态必须使用类StateManager的方法进行保存。这些状态信息必须在后面的请求是可访问的,这样,恢复视图阶段才能够读取他们。
MyFaces:
MyFaces的实现中,默认的ViewHandler是JspViewHandler,采用的方式应该是把静态的模板跟组件编码结果结合起来做渲染的方式。