当JSF处理一个initial请求的时候程序将会创建一个新的view并且将它储存在FacesContext的实例中,这里需要注意的是只有在JSF的Response指向另一个JSF的View的时候上面的过程才会执行。其实这很好理解,如果简单一个超链接或者一个按钮将请求发送到服务器,而这个请求仅仅是跳转到一个不包含任何JSF组件的页面那么在服务端将没有任何View被产生,更别说被储存在FacesContext的实例中了。
关于FacesContext实例,在其中包含了处理request的和创建response的所有需要的信息。一般国内的翻译都会将“Context”翻译为“上下文”但是笔者更愿意将其理解为“一个保存了需要信息的环境”。在FacesContext实例中可以找到此次已经创建并存储的View以及和此次request以及Response有关的所有的信息。然后程序将调用用来渲染这个view的所有的资源,最后调用renderResponse方法立即渲染这个view(上篇博客图中的标有Render Response的箭头)。
可能有些情况下JSF需要重定向到其他的系统资源比如web service或者产生一个不包含任何JSF组件的response,在这种情况下开发人员必须调用responseComplete方法跳过Render Response这个步骤(步骤图中标有Response Complete步骤的箭头),道理很简单上面的两种情况都是不需要JSF去渲染页面的,所以响应就直接结束了。
读者可以参考JSF源码(jsf-impl-2.1.3,ViewHandlerImpl.java代码片段)
......
public UIViewRoot restoreView(FacesContext context, String viewId) {
if (context == null) {
String message = MessageUtils.getExceptionMessageString
(MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "context");
throw new NullPointerException(message);
}
ExternalContext extContext = context.getExternalContext();
String mapping = Util.getFacesMapping(context);
UIViewRoot viewRoot = null;
if (mapping != null) {
if (!Util.isPrefixMapped(mapping)) {
viewId = convertViewId(context, viewId);
} else {
viewId = normalizeRequestURI(viewId, mapping);
}
}
// maping could be null if a non-faces request triggered
// this response.
if (extContext.getRequestPathInfo() == null && mapping != null &&
Util.isPrefixMapped(mapping)) {
// this was probably an initial request
// send them off to the root of the web application
try {
context.responseComplete();
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Response Complete for" + viewId);
}
extContext.redirect(extContext.getRequestContextPath());
} catch (IOException ioe) {
throw new FacesException(ioe);
}
} else {
// this is necessary to allow decorated impls.
ViewHandler outerViewHandler =
context.getApplication().getViewHandler();
String renderKitId =
outerViewHandler.calculateRenderKitId(context);
viewRoot = Util.getStateManager(context).restoreView(context,
viewId,
renderKitId);
}
return viewRoot;
}
......
上面的情况都不是我们平时常用的,仅仅是极少数的情况。在平时的开发过程当中我们遇到最常见的情况是从JSF页面跳转到另外的JSF页面。这时候就要经历图中主要的步骤(向下的箭头),转换,校验,模型更新,产生response。这与我们之前所了解的所有Web应用的处理步骤基本上是一致的。在这里需要读者注意的是在组件中有一个immediate属性,如果该组件的词属性设置为true那么JSF的生命周期将不按照正常情况进行下去。对于组件的immediate属性我们可以理解为:是否要求JSF对该组件立即(immediate)进行数据的校验(Validation)、更新值等操作,而不是在后面的步骤中进行操作,注意很多开发者认为immediate设置为true就是不进行数据的校验以及后面的一些列操作,这样理解是欠妥的。
接下来的博客将详细阐述JSF生命周期中的各个阶段的作用以及相关源码的分析。