我在使用Java 7的GlassFish 4上使用Mojarra 2.2.4。
据我所知,从BalusC对How and when is a @ViewScoped bean destroyed in JSF?的回答中,@ ViewScoped bean应该在三种情况下销毁:
我的bean在前两种情况下被销毁,但是在超过最大逻辑视图数时却没有。我已经验证,当超过最大值时,bean会 expire (我得到一个ViewExpiredException),但是在会话本身到期之前它们仍然没有被销毁。
出于内存消耗的原因,我想在第三种情况下销毁bean,特别是因为它们在到期后无法使用。
这是我的豆子:
@javax.inject.Named("sandboxController")
@javax.faces.view.ViewScoped
public class SandboxController implements Serializable {
private static final Logger log = Logger.getLogger(SandboxController.class.getName());
@PostConstruct
public void postConstruct() {
log.log(Level.INFO, "Constructing SandboxController");
}
@PreDestroy
public void preDestroy() {
log.log(Level.INFO, "Destroying SandboxController");
}
public String getData() {
return "abcdefg";
}
}
和我的sandbox.xhtml:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<body>
<h:form>
<h:outputText value="#{sandboxController.data}"/>
</h:form>
</body>
</html>
和我的web.xml的一部分:
<context-param>
<param-name>com.sun.faces.numberOfLogicalViews</param-name>
<param-value>3</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.numberOfViewsInSession</param-name>
<param-value>3</param-value>
</context-param>
如果我刷新sandbox.xhtml 50次,我会在日志中获得50份INFO: Constructing SandboxController
。无论我刷新多少次,都不会销毁bean。 VisualVM确认UIViewRoot的ViewMap仍然引用了bean。在我的全尺寸bean中,它保持了相当多的状态,我很快得到一个OutOfMemoryException。
当我手动过期会话时,我会获得50份INFO: Destroying SandboxController
。
如果我向sandbox.xhtml添加一个提交按钮并将其加载到4个不同的选项卡中,然后尝试提交第一个,我按预期得到一个ViewExpiredException,但是bean仍未被销毁。
如果我改为使用javax.faces.bean.ManagedBean和javax.faces.view.ViewScoped注释,行为是一样的。但是,OmniFaces注释org.omnifaces.cdi.ViewScoped可以正常工作。
我的@ViewScoped beans 在会话到期时被销毁,与Linked ViewScoped beans lead to memory leaks
等相关问题中描述的问题不同我不询问为什么每个bean在后续刷新时不会立即销毁 ,如下所示:JSF 2.1 ViewScopedBean @PreDestroy method is not called。我想知道为什么即使它们过期并且不再有用,它们仍然没有被破坏,因此继续消耗内存。
答案 0 :(得分:1)
我能够通过使用OmniFaces @ViewScoped注释(org.omnifaces.cdi.ViewScoped
)而不是标准的@ViewScoped(javax.faces.view.ViewScoped
)找到一个干净的解决方法。
OmniFaces ViewScoped一旦到期就会正确销毁bean。
请点击此处了解更多详情: http://showcase.omnifaces.org/cdi/ViewScoped