JSF 除了事件处理之外,总共必须经过六个阶段:
1、恢复视图阶段 Restore View Phase
2、应用请求值阶段 Apply Request Value Phase
3、验证阶段 Process Validation Phase
4、更新模型值阶段 Update Model Values Phase
5、调用应用程序阶段 Invoke Application Phase
6、渲染阶段 Render Response Phase
这六个阶段分别对应六个执行器 RestoreViewExecutor,ApplyRequestValuesExecutor,ProcessValidationsExecutor, UpdateModelValuesExecutor,InvokeApplicationExecutor,RenderResponseExecutor,且都与生命周期对象(LifecycleImpl)耦合。
在此,主要先说下第一阶段,恢复视图阶段 Restore View Phase主要做了什么,起了什么作用?
在项目中引入JSF的是javax.faces.webapp.FacesServlet类,其关联了javax.faces.lifecycle.Lifecycle,所以在JSF中生命周期的
概念是非常重要的,一直贯穿一个请求的始终。而在LIfecycle的实现类LifecycleImpl中又关联了PhaseExecutor类(是一个数组),包括: RestoreViewExecutor、ApplyRequestValuesExecutor、ProcessValidationsExecutor、 UpdateModelValuesExecutor、 InvokeApplicationExecutor、RenderResponseExecutor,这六个类共同继承了PhaseExecutor。其中RenderResponseExecutor是作一个单独的属性进行关联的。
接下来我们来先看一段RestoreViewExecutor类中的核心代码:
- public boolean execute(FacesContext facesContext)
- {
- if (facesContext == null)
- {
- throw new FacesException("FacesContext is null");
- }
- // get some required Objects
- Application application = facesContext.getApplication();
- ViewHandler viewHandler = application.getViewHandler();
- UIViewRoot viewRoot = facesContext.getViewRoot();
- RestoreViewSupport restoreViewSupport = getRestoreViewSupport(facesContext);
- // Examine the FacesContext instance for the current request. If it already contains a UIViewRoot
- if (viewRoot != null)
- {
- if (log.isLoggable(Level.FINEST))
- {
- log.finest("View already exists in the FacesContext");
- }
- // Set the locale on this UIViewRoot to the value returned by the getRequestLocale() method on the
- // ExternalContext for this request
- viewRoot.setLocale(facesContext.getExternalContext().getRequestLocale());
- restoreViewSupport.processComponentBinding(facesContext, viewRoot);
- // invoke the afterPhase MethodExpression of UIViewRoot
- _invokeViewRootAfterPhaseListener(facesContext);
- return false;
- }
- .......
首先在JSF上下文中寻找组件树(UIViewRoot),如果找到则说明视图已经存在于上下文中,这时主要做了以下几件事:
1)、把当前请求的Lacale赋给组件树。
2)、执行组件树与EL表达式的绑定。?
在这里RestoreViewExecutor关联了RestoreViewSupport类,调用了该类的一个方法:processComponentBinding
这个方法的主要作用是:
在这个方法里依赖了component这个类,循环调用了这个类的visitTree(visitContext, new RestoreStateCallback());
3)、 // invoke the afterPhase MethodExpression of UIViewRoot
_invokeViewRootAfterPhaseListener(facesContext); ?
如果找不到呢,接着来看这段代码:
- String viewId = restoreViewSupport.calculateViewId(facesContext);
- // Determine if the current request is an attempt by the
- // servlet container to display an error page.
- // If the request is an error page request, the servlet container
- // is required to set the request parameter "javax.servlet.error.message".
- final boolean errorPageRequest = facesContext.getExternalContext().getRequestMap()
- .get("javax.servlet.error.message") != null;
- // Determine if this request is a postback or an initial request.
- // But if it is an error page request, do not treat it as a postback (since 2.0)
- if (!errorPageRequest && restoreViewSupport.isPostback(facesContext))
- { // If the request is a postback
- if (log.isLoggable(Level.FINEST))
- {
- log.finest("Request is a postback");
- }
- try
- {
- facesContext.setProcessingEvents(false);
- // call ViewHandler.restoreView(), passing the FacesContext instance for the current request and the
- // view identifier, and returning a UIViewRoot for the restored view.
- viewRoot = viewHandler.restoreView(facesContext, viewId);
- if (viewRoot == null)
- {
- // If the return from ViewHandler.restoreView() is null, throw a ViewExpiredException with an
- // appropriate error message.
- throw new ViewExpiredException("No saved view state could be found for the view identifier: "
- + viewId, viewId);
- }
- // Store the restored UIViewRoot in the FacesContext.
- facesContext.setViewRoot(viewRoot);
- }
- finally
- {
- facesContext.setProcessingEvents(true);
- }
- // Restore binding
- // See https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=806
- restoreViewSupport.processComponentBinding(facesContext, viewRoot);
- }
- else
- { // If the request is a non-postback
- if (log.isLoggable(Level.FINEST))
- {
- log.finest("Request is not a postback. New UIViewRoot will be created");
- }
- //viewHandler.deriveViewId(facesContext, viewId)
- //restoreViewSupport.deriveViewId(facesContext, viewId)
- ViewDeclarationLanguage vdl = viewHandler.getViewDeclarationLanguage(facesContext,
- viewHandler.deriveLogicalViewId(facesContext, viewId));
- // viewHandler.deriveLogicalViewId() could trigger an InvalidViewIdException, which
- // it is handled internally sending a 404 error code set the response as complete.
- if (facesContext.getResponseComplete())
- {
- return true;
- }
- if (vdl != null)
- {
- ViewMetadata metadata = vdl.getViewMetadata(facesContext, viewId);
- Collection<UIViewParameter> viewParameters = null;
- if (metadata != null)
- {
- viewRoot = metadata.createMetadataView(facesContext);
- if (viewRoot != null)
- {
- viewParameters = ViewMetadata.getViewParameters(viewRoot);
- }
- else if(facesContext.getResponseComplete())
- {
- // this can happen if the current request is a debug request,
- // in this case no further processing is necessary
- return true;
- }
- }
- // If viewParameters is not an empty collection DO NOT call renderResponse
- if ( !(viewParameters != null && !viewParameters.isEmpty()) )
- {
- // Call renderResponse() on the FacesContext.
- facesContext.renderResponse();
- }
- }
- else
- {
- // Call renderResponse
- facesContext.renderResponse();
- }
- // viewRoot can be null here, if ...
- // - we don't have a ViewDeclarationLanguage (e.g. when using facelets-1.x)
- // - there is no view metadata or metadata.createMetadataView() returned null
- if (viewRoot == null)
- {
- // call ViewHandler.createView(), passing the FacesContext instance for the current request and
- // the view identifier
- viewRoot = viewHandler.createView(facesContext, viewId);
- }
- // Subscribe the newly created UIViewRoot instance to the AfterAddToParent event, passing the
- // UIViewRoot instance itself as the listener.
- // -= Leonardo Uribe =- This line it is not necessary because it was
- // removed from jsf 2.0 section 2.2.1 when pass from EDR2 to Public Review
- // viewRoot.subscribeToEvent(PostAddToViewEvent.class, viewRoot);
- // Store the new UIViewRoot instance in the FacesContext.
- facesContext.setViewRoot(viewRoot);
- // Publish an AfterAddToParent event with the created UIViewRoot as the event source.
- application.publishEvent(facesContext, PostAddToViewEvent.class, viewRoot);
- }
- // add the ErrorPageBean to the view map to fully support
- // facelet error pages, if we are in ProjectStage Development
- // and currently generating an error page
- if (errorPageRequest && facesContext.isProjectStage(ProjectStage.Development))
- {
- facesContext.getViewRoot().getViewMap()
- .put(ErrorPageWriter.ERROR_PAGE_BEAN_KEY, new ErrorPageWriter.ErrorPageBean());
- }
- // invoke the afterPhase MethodExpression of UIViewRoot
- _invokeViewRootAfterPhaseListener(facesContext);
- return false;
1、置ViewId
2、判断是否是个错误页面请求
3、如果这不是一个错误页面请求且是一个回传请求或者初始请求,
那就找出viewRoot并把它设置到facesContext?(viewHandler.restoreView(facesContext, viewId);)
4、如果这不是一个回传请求:
这边依赖于ViewHandler类生成了ViewDeclarationLanguage视图描述语言实例,
如果这个实例不为空,则:用这个实例取得视图元数据
ViewMetadata metadata = vdl.getViewMetadata(facesContext, viewId);
再用视图元数据创建ViewRoot
还用视图元数据取得视图参数viewParameter,如果有直接进入渲染环节
如果这个视图描述语言实例为空,直接进入渲染环节。
如果到这边viewRoot还是为空,则用viewHandler生成视图根目录。
viewRoot = viewHandler.createView(facesContext, viewId);(e.g. when using facelets-1.x)
否则,把viewRoot设置到FacesContext中,
Publish an AfterAddToParent event with the created UIViewRoot as the event source.
// invoke the afterPhase MethodExpression of UIViewRoot
FacesContext可以看做是一个RequestWrapper(注意这个FaceContext和ServletContext不一样,ServletContext是一个Web应用只有一个的全局对象,对应的是一个Web application,而一个FacesContext对应的是一个request,另外,RequestWrapper这个说法不严格,实际上FacesContext里面也包装了ServletContext、Response等)。而LifeCycle可以看做是一个过滤器链(类似于servlet规范里面的Filter Chain)。于是,整个JSF请求处理过程,实际上就是包装成为FaceContext的用户请求,通过类似于一个Filter Chain的LifeCycle的过程。