1
votes

So i have a problem and i kindly need any info on how to resolve this. We're using JSF 2.1 on JBoss 7.1 and we're using view scoped beans which have tables related to that view. The object represented as a row in that table is pretty big.

On every refresh of those views, a new instance of that bean is created.

To verify that this is happening, i have created a demo example:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://primefaces.org/ui">
<h:head>
</h:head>
<h:body>
        <h:outputText value="#{viewScopedBean.i}" />
</h:body>
</html> 

this template is then linked to a bean defined like this:

@ManagedBean
@ViewScoped
public class ViewScopedBean {


    private int i = 0;

    @PostConstruct
    public void init(){
        System.out.println("Init - " + i);
    }


    @PreDestroy
    public void dest(){
        System.out.println("Destroy - " + i);
    }

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }
}

Every time i refresh the view using the browser refresh button or by simply pressing enter in the browser address field, i clearly see the @PostConstruct method invocation.

If I leave the app alive for a very long time i see no @PreDestroy methods being called, and taking a heap dump shows me that ViewScopedBean has the same number of instances as the number i have reloaded the view, and the appear to remain on the heap even if i destroy the session.

This is a huge problem for me because if 500 users reloads the view with that large table, JBoss dies because it's heap space is full.

Is this the designed behavior of @ViewScoped beans or am i doing something wrong?

2

2 Answers

8
votes

View scoped beans live only as long as a user interacts with a current view by returning postbacks to the same view (by returning null/void from UICommand action methods). Returning a current view id from an action method, firing a get request to the same view, refreshing the page, manually entering URL in browser's address bar and the events like these all cause the view to be recreated. Thus, you see view scoped beans reinstantiated on every such action.

0
votes

ViewScoped beans are created every time the view created. So there it is.

But you complain that if 500 users come to the page JBoss will die. The only scope you can use to prevent that is ApplicationScope. But that is a bad idea.

Everybody will recommend you to use the narrowest scope. So I think the solution to your problem is not another scope but a "lazy load" algorithm. You should load the table page by page. I don't think everybody will need the whole table at one read.

Here is a good description of scopes. ManagedBeanScopes

If you want the bean to be destroyed you should choose requestScope. Because viewscoped beans stored in the session.