"绑定"属性如何在JSF中起作用?应该何时以及如何使用?

Joh*_*ohn 74 jsf binding components jsf-2

在JSF中有很多材料区分value属性和binding属性.

我对这两种方法如何彼此不同感兴趣.鉴于:

public class User {
    private String name;
    private UICommand link;

    // Getters and setters omitted.
}
Run Code Online (Sandbox Code Playgroud)
<h:form>
    <h:commandLink binding="#{user.link}" value="#{user.name}" />
</h:form>
Run Code Online (Sandbox Code Playgroud)

value指定属性时会发生什么变化.getter运行以返回bean 的name属性值User.该值将打印到HTML输出.

但我无法理解它是如何binding运作的.生成的HTML如何维护与bean link属性的绑定User

下面是手动美化和注释后生成的输出的相关部分(注意id j_id_jsp_1847466274_1是自动生成的,并且有两个隐藏的输入小部件).我正在使用Sun的JSF RI 1.2版.

<form action="/TestJSF/main.jsf" enctype="application/x-www-form-urlencoded"
    id="j_id_jsp_1847466274_1" method="post"  name="j_id_jsp_1847466274_1">
    <input name="j_id_jsp_1847466274_1" type="hidden" value="j_id_jsp_1847466274_1">
    <a href="#" onclick="...">Name</a>
    <input autocomplete="off" id="javax.faces.ViewState" name="javax.faces.ViewState"
        type="hidden" value="-908991273579182886:-7278326187282654551">
</form>
Run Code Online (Sandbox Code Playgroud)

在哪里binding存放在这里?

Bal*_*usC 125

它是如何工作的?

当构建/恢复JSF视图(Facelets/JSP文件)时,将生成JSF组件树.此时,视图构建时间,所有binding属性都被评估(连同id属性和标记处理程序,如JSTL).当需要在添加到组件树之前创建JSF组件时,JSF将检查该binding属性是否返回预先创建的组件(即非null),如果是,则使用它.如果它不是预先创建的,那么JSF将以"通常的方式"自动创建组件,并binding使用自动处理的组件实例作为参数调用setter behind 属性.

在效果中,它将组件树中的组件实例的引用绑定到范围变量.在生成的组件本身的HTML表示中,此信息无法显示.无论如何,此信息与生成的HTML输出无关.提交表单并恢复视图时,JSF组件树只是从头开始重建,所有binding属性都将重新评估,如上段所述.重新创建组件树后,JSF会将JSF视图状态还原到组件树中.

组件实例是请求作用域!

了解和理解的重要一点是具体的组件实例是有效的请求范围.它们是在每个请求上新创建的,它们的属性在恢复视图阶段由JSF视图状态填充.因此,如果将组件绑定到辅助bean的属性,那么支持bean 绝对不应该在比请求范围更广的范围内.另请参见JSF 2.0规范第3.1.5节:

3.1.5组件绑定

...

组件绑定通常与通过Managed Bean Creation工具动态实例化的JavaBeans一起使用(请参见第5.8.1节"VariableResolver和Default VariableResolver").强烈建议应用程序开发人员在"请求"范围内放置由组件绑定表达式指向的托管bean.这是因为将它放在会话或应用程序范围中需要线程安全,因为UIComponent实例依赖于在单个线程内部运行.在"会话"范围内放置组件绑定时,对内存管理也可能产生负面影响.

否则,组件实例在多个请求之间共享,可能导致" 重复组件ID "错误和"怪异"行为,因为视图中声明的验证器,转换器和侦听器将从先前的请求重新附加到现有组件实例.症状很明显:它们被执行多次,每次请求的次数都与组件绑定的范围相同.

而且,在负载很重的情况下(即当多个不同的HTTP请求(线程)同时访问和操作同一个组件实例时),您可能迟早会面临应用程序崩溃,例如UIComponent.popComponentFromEL上的Stuck线程Java线程在使用richfaces UIDataAdaptorBase及其内部HashMap时,CPU利用率为100%,甚至是一些"奇怪的" IndexOutOfBoundsExceptionConcurrentModificationException直接来自JSF实现源代码,而JSF正在忙于保存或恢复视图状态(即堆栈跟踪指示saveState()restoreState()方法等).

使用binding一个bean属性是不好的做法

无论如何,使用binding这种方式,将整个组件实例绑定到bean属性,即使在请求范围的bean上,也是在JSF 2.xa中相当罕见的用例,通常不是最佳实践.它表明了一种设计气味.你通常在观察侧声明组件,把他们的运行属性,例如value,也许其他人一样styleClass,disabled,rendered,等,正常的bean属性.然后,您只需操作您想要的bean属性,而不是抓取整个组件并调用与该属性关联的setter方法.

在当一个组件需要"动态生成"的情况下基于静态模型,更好的方法是使用视图构建时间标签,如JSTL,如果有必要的标记文件,而不是createComponent(),new SomeComponent(),getChildren().add(),什么不是.另请参见如何将旧JSP的片段重构为某些JSF等效项?

或者,如果一个组件需要"动态呈现"基于动态模型,然后只需使用一个迭代器组件(<ui:repeat>,<h:dataTable>,等).另请参见如何动态添加JSF组件.

复合组件是一个完全不同的故事.将内部组件绑定<cc:implementation>到支持组件(即由...标识的组件)是完全合法的<cc:interface componentType>.另请参阅ao Split java.util.Date over two h:inputText字段表示小时和分钟,其中f:convertDateTime以及如何实现动态列表一个JSF 2.0复合组件?

binding在本地范围内使用

但是,有时您希望了解特定组件内部不同组件的状态,而不仅仅是与操作/值相关验证相关的用例.为此,binding可以使用该属性,但不能与bean属性结合使用.您可以在binding属性中指定本地EL范围中的唯一变量名称,binding="#{foo}"并且该组件在同一视图中的其他位置的渲染响应期间直接作为UIComponent可用的参考#{foo}.以下是几个相关问题,其中答案中使用了这样的解决方案:

也可以看看:


归档时间:

查看次数:

97491 次

最近记录:

9 年,12 月 前