它是如何工作的?
构建/恢复JSF视图(Facelets / JSP文件)时,将生成JSF组件树。那时,将对视图构建时间,所有binding
属性(以及id
属性和标记处理程序(如JSTL))进行评估。当需要在将JSF组件添加到组件树之前创建JSF组件时,JSF将检查该binding
属性是否返回一个预先创建的组件(即non null
),如果是,则使用它。如果未预先创建,则JSF将以“通常的方式”自动创建组件,并binding
使用自动创建的组件实例作为参数来调用属性后面的setter 。
实际上,它会将组件树中组件实例的引用绑定到作用域变量。在组件本身的生成的HTML表示中,该信息绝不是可见的。无论如何,此信息绝不与生成的HTML输出相关。提交表单并还原视图后,JSF组件树仅从头开始重建,所有binding
属性都将如上段所述重新进行评估。重新创建组件树之后,JSF会将JSF视图状态恢复到组件树中。
组件实例是请求范围的!
重要的是要知道和理解的是,具体的组件实例是有效地请求范围的。它们是在每个请求上新创建的,并且它们的属性在还原视图阶段被JSF视图状态的值填充。因此,如果将组件绑定到支持Bean的属性,则支持Bean绝对不应在比请求范围更广的范围内。另请参见JSF 2.0规范第3.1.5章:
3.1.5组件绑定
...
组件绑定通常与通过受管Bean创建工具动态实例化的JavaBean结合使用(请参见第5.8.1节“ VariableResolver和默认VariableResolver”)。强烈建议应用程序开发人员将由组件绑定表达式指向的托管bean置于“请求”范围内。这是因为将其放置在会话或应用程序范围内将需要线程安全,因为UIComponent实例取决于在单个线程内部运行。将组件绑定置于“会话”范围中时,也可能对内存管理产生负面影响。
否则,组件实例将在多个请求之间共享,这可能会导致“重复的组件ID ”错误和“怪异”的行为,因为视图中声明的验证器,转换器和侦听器已从先前的请求重新附加到现有组件实例。症状很明显:它们执行了多次,在与该组件绑定的范围相同的范围内,每个请求重复执行一次。
并且,在繁重的负载下(即,当多个不同的HTTP请求(线程)同时访问和操作相同的组件实例时),您可能迟早会遇到应用程序崩溃,例如UIComponent.popComponentFromEL上的Stuck线程或Java Threads在JSF忙于保存或恢复视图状态(即堆栈跟踪指示或方法等)的情况下,使用richfaces UIDataAdaptorBase及其内部HashMap或什至有些“奇怪”IndexOutOfBoundsException
或ConcurrentModificationException
直接来自JSF实现源代码以100%CPU使用率。saveState()
restoreState()
使用binding
一个bean属性是不好的做法
无论如何,binding
在JSF 2.xa中,即使是在请求范围的bean上,使用这种方法将整个组件实例绑定到Bean属性也是相当罕见的用例,通常不是最佳实践。表示设计气味。你通常在观察侧声明组件,把他们的运行属性,如value
,或许别人喜欢styleClass
,disabled
,rendered
,等,正常的bean属性。然后,您只需要精确地操作所需的bean属性,而不是获取整个组件并调用与该属性关联的setter方法。
在情况下,当进行“动态生成”一个组件需要基于静态模型,更好的方法是使用视图构建时间标签,如JSTL,如果有必要的标记文件,而不是createComponent()
,new SomeComponent()
,getChildren().add()
,什么不是。另请参见如何将旧JSP的代码段重构为等效的JSF?
或者,如果要“动态呈现”组件的需求基础上的动态模型,然后只需使用一个迭代器组件(<ui:repeat>
,<h:dataTable>
,等)。另请参阅如何动态添加JSF组件。
复合组件是一个完全不同的故事。将a<cc:implementation>
中的组件绑定到支持组件(即由标识的组件)是完全合法的<cc:interface componentType>
。另请参见在两个h:inputText字段上使用f:convertDateTime和如何使用以下代码实现动态列表来拆分java.util.Date JSF 2.0复合组件?
仅binding
在本地范围内使用
但是,有时您想从特定组件内部了解不同组件的状态,而在与动作/值相关的验证相关的用例中,这种情况要多得多。为此,binding
可以使用该属性,但不能与bean属性结合使用。您可以binding
像这样在属性中在本地EL作用域中指定一个唯一变量名称,binding="#{foo}"
并且该组件在渲染响应期间正在同一视图中的其他地方直接作为UIComponent
引用提供#{foo}
。以下是在答案中使用了此类解决方案的几个相关问题:
也可以看看:
User.User(), User.getLink(), User.setLink(), User.getValue()
当我点击链接=User.User(), User.setLink()...