Jsf 为什么渲染属性会多次调用getter?
与前面的一个示例相关,我尝试在服务器上监视我的get/set方法(调用它们的时间和频率)。因此,我的实际情况是:Jsf 为什么渲染属性会多次调用getter?,jsf,jsf-2,facelets,getter,Jsf,Jsf 2,Facelets,Getter,与前面的一个示例相关,我尝试在服务器上监视我的get/set方法(调用它们的时间和频率)。因此,我的实际情况是: @ManagedBean(name="selector") @RequestScoped public class Selector { @ManagedProperty(value="#{param.profilePage}") private String profilePage; public String getProfilePage() {
@ManagedBean(name="selector")
@RequestScoped
public class Selector {
@ManagedProperty(value="#{param.profilePage}")
private String profilePage;
public String getProfilePage() {
if(profilePage==null || profilePage.trim().isEmpty()) {
this.profilePage="main";
}
System.out.println("GET "+profilePage);
return profilePage;
}
public void setProfilePage(String profilePage) {
this.profilePage=profilePage;
System.out.println("SET "+profilePage);
}
}
唯一可以调用此方法的页面(它只在呈现时调用get方法)是:
什么?它调用了七次getProfilePage()
方法?(还有1次setProfilePage()
)
我想知道为什么会有这种行为:)
谢谢
添加了一个示例
豆子
profile.xhtml
<h:panelGroup layout="block" id="profileContent">
<h:panelGroup layout="block" styleClass="content_title">
Profilo Utente
</h:panelGroup>
<h:panelGroup rendered="#{selector.profilePage=='main'}">
<ui:include src="/profile/profile_main.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{selector.profilePage=='edit'}">
<ui:include src="/profile/profile_edit.xhtml" />
</h:panelGroup>
</h:panelGroup>
// profile_main.xhtml
<h:form id="formProfileMain" prependId="false">
<h:panelGroup layout="block" styleClass="content_span">
<h:outputScript name="jsf.js" library="javax.faces" target="head" />
<h:panelGroup layout="block" styleClass="profilo_3">
<h:commandButton value="EDIT">
<f:setPropertyActionListener target="#{selector.profilePage}" value="edit" />
<f:ajax event="action" render=":profileContent"/>
</h:commandButton>
</h:panelGroup>
</h:panelGroup>
</h:form>
// profile_edit.xhtml
<h:form id="formProfileEdit" prependId="false">
<h:panelGroup layout="block" styleClass="content_span">
<h:outputScript name="jsf.js" library="javax.faces" target="head" />
<h:panelGroup layout="block" styleClass="profilo_3">
<h:commandButton value="Edit">
<f:setPropertyActionListener target="#{selector.profilePage}" value="editProfile" />
<f:ajax event="action" render=":profileContent"/>
</h:commandButton>
<h:commandButton value="Back">
<f:setPropertyActionListener target="#{selector.profilePage}" value="main" />
<f:ajax event="action" render=":profileContent"/>
</h:commandButton>
</h:panelGroup>
</h:panelGroup>
</h:form>
profilounte
//profile_main.xhtml
//profile_edit.xhtml
在本例中,我调用profile_main(默认);在(例如)我调用profile_edit(通过单击edit)之后;之后,单击“上一步”返回profile_main。现在,如果我想重新加载profile_edit(编辑),我需要多次单击该命令按钮。为什么?EL(表达式语言,那些{}
东西)不会缓存调用的结果。它只是直接访问bean中的数据。如果getter只返回数据,这通常不会造成损害
setter调用由@ManagedProperty
完成。其基本功能如下:
selector.setProfilePage(request.getParameter("profilePage"));
getter调用都是在呈现响应阶段通过rendered=“#{selector.profilePage=='some'}”
完成的。当它在中第一次计算false
时,将不再执行任何调用。当它计算为true
时,将按照以下顺序再重新计算六次:
呈现的
属性,则在应用请求值阶段也将对其进行评估,作为防止篡改/黑客请求的一部分
没错,这看起来既笨拙又低效。它被认为是JSF的致命伤。建议删除所有这些重复检查,并坚持在UIComponent\encodeAll()
中完成的检查,或在每个阶段对isRendered()
进行评估,很明显,问题的根源在于EL,而不是JSF,使用CDI可以大大提高性能。所以没有必要从JSF规范的角度来解决这个问题
如果您担心托管属性在其设置为空或空后只检查一次,则考虑将其移动到一个用<代码> @ PrimeStudio注释的方法。这种方法将在bean的构造和所有依赖项注入之后直接调用
@PostConstruct
public void init() {
if (profilePage == null || profilePage.trim().isEmpty()) {
profilePage = "main";
}
}
另见:
请参阅,了解更多信息。可能重复了这个问题:我读了这篇文章,但它没有解释为什么多次调用getMethod。这使我现在在AJAX调用中遇到了一些问题(似乎是写/重写了一些bean属性)。是的,但是我如何指定,我只有一个
{selector.profilePage}
在一个页面中。这就是我不理解的:)我没有仔细观察JSF2.0中的行为,因为它特别便宜,所以不值得进行微优化,但您可能需要添加一个Thread.dumpStack()
给getter,让他知道这个调用是从哪里开始的,并从FacesContext.getCurrentInstance().getPhaseId()
中选择一个sysout来了解它现在处于哪个阶段。嗯,好吧,理解这一点更复杂:)我想在jsf上编程时我不应该介意它(只是我想知道我是否做错了什么)。但似乎发生在所有人身上。好的,我在构造后初始化它:)添加了一个示例。如果这个主题将被关闭,或者这个问题是无关的,我将打开一个新的:)让我知道一个人:)因此,如果我使用@ManagedProperty
(例如selector.setProfilePage(request.getParameter(“profilePage”);
)并且我使用这个值只是为了获取param(不是我的情况),我可以删除public void setProfilePage(String profilePage){this.profilePage=profilePage;}
(我不会这么做,这是一个bean,也许我将来会使用它)。现在很清楚为什么它多次调用getter方法:)我不明白的是为什么我的代码仍然不能正常工作:我必须多次单击按钮来设置profilePage属性(ajax调用启动,但bean似乎不会自我更新
<h:panelGroup layout="block" id="profileContent">
<h:panelGroup layout="block" styleClass="content_title">
Profilo Utente
</h:panelGroup>
<h:panelGroup rendered="#{selector.profilePage=='main'}">
<ui:include src="/profile/profile_main.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{selector.profilePage=='edit'}">
<ui:include src="/profile/profile_edit.xhtml" />
</h:panelGroup>
</h:panelGroup>
// profile_main.xhtml
<h:form id="formProfileMain" prependId="false">
<h:panelGroup layout="block" styleClass="content_span">
<h:outputScript name="jsf.js" library="javax.faces" target="head" />
<h:panelGroup layout="block" styleClass="profilo_3">
<h:commandButton value="EDIT">
<f:setPropertyActionListener target="#{selector.profilePage}" value="edit" />
<f:ajax event="action" render=":profileContent"/>
</h:commandButton>
</h:panelGroup>
</h:panelGroup>
</h:form>
// profile_edit.xhtml
<h:form id="formProfileEdit" prependId="false">
<h:panelGroup layout="block" styleClass="content_span">
<h:outputScript name="jsf.js" library="javax.faces" target="head" />
<h:panelGroup layout="block" styleClass="profilo_3">
<h:commandButton value="Edit">
<f:setPropertyActionListener target="#{selector.profilePage}" value="editProfile" />
<f:ajax event="action" render=":profileContent"/>
</h:commandButton>
<h:commandButton value="Back">
<f:setPropertyActionListener target="#{selector.profilePage}" value="main" />
<f:ajax event="action" render=":profileContent"/>
</h:commandButton>
</h:panelGroup>
</h:panelGroup>
</h:form>
selector.setProfilePage(request.getParameter("profilePage"));
@PostConstruct
public void init() {
if (profilePage == null || profilePage.trim().isEmpty()) {
profilePage = "main";
}
}