@ViewScoped 在每个回发请求上调用 @PostConstruct
Posted
技术标签:
【中文标题】@ViewScoped 在每个回发请求上调用 @PostConstruct【英文标题】:@ViewScoped calls @PostConstruct on every postback request 【发布时间】:2011-07-29 08:20:54 【问题描述】:这似乎不对。我正在清理我的代码,我才注意到这一点。每个 ajax 请求都在触发我的 @ViewScoped
bean 的构造函数和 @PostConstruct
。即使是简单的数据库分页也会触发它。
我 understood 认为 @ViewScoped
比 @RequestScoped
长,并且不应该在每次请求时都重新构建它。仅在通过 GET 重新加载完整页面后。
【问题讨论】:
【参考方案1】:换句话说,您的@ViewScoped
bean 的行为类似于@RequestScoped
bean。它在每个回发请求中都从头开始重新创建。这有很多可能的原因,其中大部分归结为相关的 JSF 视图在 JSF 状态下不再可用,而 JSF 状态又默认与 HTTP 会话相关联。
如果您可以确保 HTTP 会话本身不是问题的根本原因,即当 @SessionScoped
工作正常时,请查看以下可能原因列表。否则,如果 HTTP 会话本身也被丢弃并在每个请求上重新创建,那么您需要退后一步,查看会话 cookie 和服务器配置。任何与 HTTP 会话中断相关的原因至少都超出了 JSF 的上下文。
您使用的是 Mojarra 2.1.17 或更早版本,并且视图包含 EL 表达式,这些表达式将视图范围的 bean 属性绑定到在view build time 期间评估的标记属性。例如 JSTL <c:if>
、<c:forEach>
等或 JSF <ui:include>
、<x:someComponent id="#..."
、<x:someComponent binding="#...">
等。这是由 Mojarra (issue 1496) 中的错误引起的。另见Why does @PostConstruct callback fire every time even though bean is @ViewScoped? JSF
这已在 Mojarra 版本 2.1.18 中修复。如果您无法升级到较新的版本,解决方法是在web.xml
中禁用部分状态保存,另见JSTL in JSF2 Facelets... makes sense?
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
或者当您只想针对一组特定的 JSF 视图时:
<context-param>
<param-name>javax.faces.FULL_STATE_SAVING_VIEW_IDS</param-name>
<param-value>/foo.xhtml;/bar.xhtml;/folder/baz.xhtml</param-value>
</context-param>
重要的是,将 JSF 组件的 id
或 binding
属性的值绑定到视图范围的 bean 属性是一种不好的做法。这些确实应该绑定到请求范围的 bean 属性,或者应该寻求替代方案。另见How does the 'binding' attribute work in JSF? When and how should it be used?
您使用的是 Mojarra 2.2.0,只有该版本在维护 2.2.1 中已修复的视图范围方面存在(但未知)错误,另请参见 issue 2916。解决方案是升级到新版本。
@ViewScoped
注解是从错误的包中导入的。 JSF 提供了两个@ViewScoped
注释,一个来自javax.faces.bean
包,用于用@ManagedBean
注释的JSF 托管bean,另一个来自javax.faces.view
包,用于用@Named
注释的CDI 托管bean。当 bean 作用域注解与 bean 管理注解不匹配时,那么实际的 bean 作用域将成为 bean 管理框架的默认作用域,在 JSF 托管 bean 中为 @RequestScoped
,在 CDI 托管 bean 中为 @Dependent
。
您需要确保您拥有以下任一构造并且不要混合使用它们,另请参阅@ViewScoped bean recreated on every postback request when using JSF 2.2。
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
@ManagedBean
@ViewScoped
public class CorrectJSFViewScopedBean implements Serializable
import javax.inject.Named;
import javax.faces.view.ViewScoped;
@Named
@ViewScoped
public class CorrectCDIViewScopedBean implements Serializable
视图(意外地?)通过<f:view transient="true">
标记为瞬态。这基本上开启了“无状态 JSF”,这是自 Mojarra 2.1.19 以来的新功能。因此,JSF 视图根本不会保存在 JSF 状态中,逻辑结果是所有引用的视图范围 bean 不能再与 JSF 视图相关联。另见What is the usefulness of statelessness in JSF?
Web 应用程序配置了 com.sun.faces.enableRestoreView11Compatibility
上下文参数设置为 true
以错误地尝试“避免”ViewExpiredException
。使用此上下文参数,ViewExpiredException
将永远不会被抛出,但视图(以及所有关联的视图范围 bean)只会从头开始重新创建。但是,如果每个请求都发生这种情况,那么这种方法实际上隐藏了另一个问题:视图过期太快了。这表明在维护 JSF 视图状态和/或 HTTP 会话时可能存在问题。如何正确解决/配置该问题,请前往javax.faces.application.ViewExpiredException: View could not be restored。
Web 应用程序的运行时类路径被多个不同版本的 JSF API 或 impl 相关类污染。这会导致 JSF 视图状态的标识符/标记出现损坏/不匹配。您需要确保 webapp 的 /WEB-INF/lib
中没有多个 JSF API JAR 文件。如果您使用 Maven,请确保将服务器提供的库标记为 <scope>provided</scope>
。另请参阅our JSF wiki page 中的“安装 JSF”部分以及此相关问题的答案:How to properly install and configure JSF libraries via Maven?。
当您使用 PrimeFaces <p:dialog>
时,请确保 <p:dialog>
有自己的 <h:form>
,并且它没有嵌套在另一个 <h:form>
中。另见p:fileUpload inside p:dialog losing @ViewScoped values。
当您将 PrimeFaces FileUploadFilter
与 PrettyFaces 结合使用时,请确保 FileUploadFilter
也在 PrettyFaces 重写/转发的请求上运行。另见ViewScoped bean rebuilt when FileUploadListener called using PrettyFaces 和How to use PrimeFaces p:fileUpload? Listener method is never invoked or UploadedFile is null / throws an error / not usable。
当您使用 PrettyFaces 时,将 CSS/JS/图像资源重定向到与 @ViewScoped
bean 绑定的 JSF 页面的错误配置的重写规则也会产生误导行为。另见CDI ViewScope & PrettyFaces: Multiple calls to @PostConstruct (JSF 2.2)。
【讨论】:
你的正确。我在我的页面上使用 c:foreach 的网站添加了一个功能。难怪我之前没有注意到。问题是 ui:repeat 在我的情况下不起作用。 primefaces.prime.com.tr/forum/viewtopic.php?f=3&t=59 部分状态保存是否适用于 c:for each? 很遗憾,不,禁用部分状态保存并不能解决 JSTL 标签的问题。然而,这种特殊情况很棘手。从理论上讲,您可以使用一个完整的组件来解决这个问题,例如<p:tabs>
接受集合而不是 <ui:repeat><p:tab>
。我相信这曾经是作为 PrimeFaces 的功能请求发布的,不确定 Cagatay 对它做了什么。
PARTIAL_STATE_SAVING 改变了我的生活
@Danijel:只使用rendered
属性?另见***.com/a/4870557 和***.com/a/15947948。或者,只需升级到 Mojarra 2.1.18 或更高版本。从那以后它就被修复了。
谢谢。使用 以上是关于@ViewScoped 在每个回发请求上调用 @PostConstruct的主要内容,如果未能解决你的问题,请参考以下文章
JSF ViewScoped bean 在所有 ajax 请求中的唯一 ID?
p:remoteCommand 销毁 @ViewScoped 托管 bean