调试 JSF 生命周期——每个阶段到底发生了啥

Posted

技术标签:

【中文标题】调试 JSF 生命周期——每个阶段到底发生了啥【英文标题】:Debugging JSF Life Cycle - what exactly happens in each phase调试 JSF 生命周期——每个阶段到底发生了什么 【发布时间】:2014-03-21 18:35:09 【问题描述】:

我决定完全深入研究 JSF 2.0,因为我的项目需要深入了解它。我正在阅读JSF Lifecyle Debug,这是一篇关于 JSF 生命周期的精彩文章。在阅读本文时,我有以下困惑。

    如果是初始请求,则在Restore View Phase 中创建一个空视图并直接发生Render Response Phase。此时没有要保存的状态。那么render response phase 到底发生了什么?我在运行示例时有点困惑。

    文章指出,检索到的输入值在Apply Request Values 阶段设置在inputComponent.setSubmittedValue() 中。如果验证和转换通过,则在inputComponent.setValue(value)inputComponent.setSubmittedValue(null) 运行中设置该值。在同一点文章指出,现在如果在下一个回发请求中更改了值,则将其与每次回发时始终为空的提交值进行比较,将调用 value change listener。这意味着如果我们甚至不更改值,因为提交的值将为空,那么 valueChangeListener 将始终被调用?我对这个说法感到困惑。有人可以详细说明一下吗?

    文章说明了immediate 属性的用法。如果在输入组件上设置了immediate 属性,则理想情况下会跳过Process Validation Phase,但所有转换和验证都发生在Apply Request Values 中。我的观点是,仍然在进行转换和验证时,跳过第三阶段有什么好处?

    检索值是什么意思?

    我想知道,如果假设视图上有五个字段。 JSF 是否会列出这些值的一些集合并 Apply Request ValuesProcess Validations 阶段逐一迭代它们?

    在本文的最后一点,它说明了何时使用immediate 属性。据我了解,如果在输入组件和命令组件中都设置了立即属性,它将跳过从应用请求值到调用应用程序的阶段,以获取任何不具有immediate 的属性。那么最后一条语句是什么意思是登录表单中的“忘记密码”按钮,其中包含必填且立即的用户名字段和必填但非立即的密码字段。

我知道这些是非常基本的混淆,但明确这些主题肯定有助于提高 JSF 知识。

【问题讨论】:

【参考方案1】:

1:那么在渲染响应阶段实际发生了什么?

为客户端生成 html 输出,从 UIViewRoot#encodeAll() 开始。您可以通过右键单击在 webbrowser 中查看结果 View Source(因此不能通过右键单击,在 webbrowser Inspect Element,因为这只会显示 webbrowser 的 HTML DOM 树已基于原始 HTML 源代码和之后的所有 javascript 事件构建)。


2:与提交的值进行比较,每次回发时该值始终为空

不,它是作为实例变量保存的。 JSF 不会调用getSubmittedValue() 来比较它。


3:我的意思是,仍然在进行转换和验证时,跳过第三阶段有什么好处?

这在文章底部的Okay, when should I use the immediate attribute? 下得到了回答。简而言之:优先验证。如果带有immediate="true" 的组件在转换/验证时失败,那么没有immediate="true" 的组件将不会被转换/验证。


4:检索值是什么意思?

最终用户提交的“原始”值(最终用户在输入表单中输入的确切输入值)。这通常是String。如果您熟悉 servlet,那么很容易理解,这正是您通过request.getParameter() 获得的值。


5:JSF 是否会列出这些值的一些集合,并在应用请求值和流程验证阶段逐一迭代它们?

几乎。该集合已经存在于 JSF 组件树的风格中。因此,JSF 基本上迭代了一个树结构,从 FacesContext#getUIViewRoot() 开始。


6:那么最后一条语句的含义是什么意思是登录表单中的“忘记密码”按钮,其中包含必填且立即的用户名字段和必填但非立即的密码字段。

这样您就可以在“忘记密码”的情况下重复使用登录表单。如果您提交“登录”按钮,那么显然必须验证用户名和密码字段。但是,如果您提交“忘记密码”按钮,则不应验证密码字段。


也就是说,您可能会发现以下 JSF 阶段/生命周期备忘单对快速参考也很有用:

fc = FacesContext vh = ViewHandler in = UIInput rq = HttpServletRequest id = in.getClientId(fc);

1 RESTORE_VIEW

String viewId = rq.getServletPath();
fc.setViewRoot(vh.createView(fc, viewId));

2APPLY_REQUEST_VALUES

in.setSubmittedValue(rq.getParameter(id));

3PROCESS_VALIDATIONS

Object value = in.getSubmittedValue();
try 
   value = in.getConvertedValue(fc, value);
   for (Validator v : in.getValidators())
      v.validate(fc, in, value);
   
   in.setSubmittedValue(null);
   in.setValue(value);
 catch (ConverterException | ValidatorException e) 
   fc.addMessage(id, e.getFacesMessage());
   fc.validationFailed(); // Skips phases 4+5.
   in.setValid(false);

4UPDATE_MODEL_VALUES

bean.setProperty(in.getValue());

5INVOKE_APPLICATION

bean.submit();

6RENDER_RESPONSE

vh.renderView(fc, fc.getViewRoot());

另见:

Difference between Apply Request Values and Update Model Values JSF - Another question on Lifecycle What's the view build time?

【讨论】:

一如既往的好@BalusC。太感谢了。专家的另一个出色回答。老实说,我很荣幸。

以上是关于调试 JSF 生命周期——每个阶段到底发生了啥的主要内容,如果未能解决你的问题,请参考以下文章

jsf和facelets的生命周期

J2EE作业_JSF和facelets的生命周期

react生命周期,以及各个周期都做了啥

了解带有和不带有重定向的 JSF 生命周期阶段

react 生命周期

Lifecycle of JSF and Facelets(第6周)