2012-08-29 16 views
6

In unserem JavaEE6 Projekt (EJB3, JSF2) auf JBoss 7.1.1, es scheint, dass wir @ViewScoped ein Speicherleck mit SeamFaces haben.Speicherleck mit ViewScoped Bean?

Wir machten einen kleinen Prototyp, die Tatsache zu überprüfen:

  • wir JMeter verwenden, um rufen eine Seite 200mal;
  • die Seite enthält und ruft eine viewscoped Bean, die eine Stateful EJB injiziert;
  • wir die Session-Timeout 1 Minute zu beheben.

Am Ende des Tests prüfen wir den Inhalt des Speichers mit VisualVM, und hier, was wir haben:

  • mit einer @ViewScoped Bohne, bekommen wir noch 200 Fälle von der Stateful MyController - und die @PreDestroy Methode wird nie aufgerufen;
  • mit einer @ConversationScoped Bohne wird @preDestroy Methode eine der Sitzung Ende und dann bekamen wir einen sauberen Speicher genannt.

Verwenden wir den Ansichtsbereich schlecht oder handelt es sich wirklich um einen Fehler?


Hier ist die XHTML-Seite:

<!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:f="http://java.sun.com/jsf/core" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:ui="http://java.sun.com/jsf/facelets" 
    xmlns:s="http://jboss.org/seam/faces"> 
    <f:metadata> 
     <f:viewParam name="u" value="#{myBean.uselessParam}" /> 
     <s:viewAction action="#{myBean.callService}" /> 
    </f:metadata> 
    <h:body > 
     <f:view> 
     </f:view> 
    </h:body>  
</html> 

nun die mitgelieferte Bohne myBean. Für die Variante sind alle kommentierten Teile unkommentiert.

@ViewScoped 
// @ConversationScoped 
@Named 
public class MyBean implements Serializable 
{ 
    @Inject 
    MyController myController; 
    //@Inject 
    //Conversation conversation; 

    private String uselessParam; 

    public void callService() 
    { 
     //if(conversation.isTransient()) 
     //{ 
     //   conversation.begin(); 
     //} 
     myController.call(); 
    } 

    public String getUselessParam() 
    { 
     return uselessParam; 
    } 

    public void setUselessParam(String uselessParam) 
    { 
     this.uselessParam = uselessParam; 
    } 
} 

Und dann die injizierte Stateful Bean MyController:

@Stateful 
@LocalBean 
public class MyController 
{ 
    public void call() 
    { 
     System.out.println("call "); 
    } 

    @PreDestroy 
    public void destroy() 
    { 
     System.out.println("Destroy"); 
    } 
} 

Antwort

5

Ich sehe viele Entwickler sind zufrieden mit @ViewAccessScoped in Myface CODI. Könnten Sie es bitte versuchen und das Feedback sagen.

+2

Wir versuchten mit CODI und der Test ging gut. Nett! –

3

Chancen sind dies ein Fehler ist. Ehrlich gesagt war die Implementierung von Seam 3 nicht so toll und die CODI-Version (und auch was in DeltaSpike sein wird) ist viel besser.

5

Ich habe das oben genannte Problem in JSF verwaltet @ViewScoped Bean konfrontiert. Nach dem Hinweis auf einige Blogs habe ich verstanden, dass JSF Ansicht Bohne Staaten in http-Sitzung speichert und wird nur zerstört, wenn Sitzung für ungültig erklärt wird. Immer wenn wir auf die jsf-Seite klicken, wird jedes Mal eine neue View-Scope-Bean erstellt, die auf die Seite verweist. Ich habe mit Spring Custom View Scope gearbeitet. Es funktioniert gut. Unten ist der Detailcode.

für JSF 2.1:

Schritt 1: Erstellen Sie eine Ansicht Scope Bean Beitrag Listener Konstrukt wie folgt.

Schritt 2: Ereignislistener in faces-config registrieren.xml

Schritt 3: Erstellen Sie wie folgt eine benutzerdefinierte Ansichtsbereich-Bean.

public class ViewScope implements Scope { 

    @Override 
    public Object get(String name, ObjectFactory objectFactory) { 
     Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap(); 
      if (viewMap.containsKey(name)) { 
        return viewMap.get(name); 
      } else { 
       List<Map<String, Object>> activeViewMaps = (List<Map<String, Object>>) 
       FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("com.org.jsf.activeViewMaps"); 
       if (activeViewMaps != null && !activeViewMaps.isEmpty() 
        && activeViewMaps.size() > 1) { 
         Iterator iterator = activeViewMaps.iterator(); 
        if (iterator.hasNext()) { 
          Map<String, Object> oldViewMap = (Map<String, Object>) 
          iterator.next(); 
          oldViewMap.clear(); 
          iterator.remove(); 
        } 
        } 
       Object object = objectFactory.getObject(); 
       viewMap.put(name, object); 
       return object; 
      } 

    } 

Hinweis: Andere überschriebene Methoden können leer sein.

für JSF 2.2:

JSF 2.2 speichert die navigierte Ansicht Karten in http-Sitzung in 'com.Sun.faces.application.view.activeViewMaps' als Schlüssel. Fügen Sie den folgenden Code in den benutzerdefinierten Bereich für die benutzerdefinierte Ansicht ein. Kein Bedarf an Zuhörern wie in JSF 2.1

public class ViewScope implements Scope { 

    public Object get(String name, ObjectFactory objectFactory) { 
     Map<String, Object> viewMap = 
      FacesContext.getCurrentInstance().getViewRoot().getViewMap(); 
       if (viewMap.containsKey(name)) { 
        return viewMap.get(name); 
       } else { 
         LRUMap lruMap = (LRUMap) FacesContext.getCurrentInstance(). 
    getExternalContext().getSessionMap().get("com.sun.faces.application.view.activeViewMaps"); 
       if (lruMap != null && !lruMap.isEmpty() && lruMap.size() > 1) { 
        Iterator itr = lruMap.entrySet().iterator(); 
        while (itr.hasNext()) {//Not req 
        Entry entry = (Entry) itr.next(); 
        Map<String, Object> map = (Map<String, Object>) entry.getValue(); 
        map.clear(); 
        itr.remove(); 
        break; 
        } 
       } 
       Object object = objectFactory.getObject(); 
       viewMap.put(name, object); 
       return object; 
     } 
} 
+0

können Sie bitte die Importe für LRUMap und andere in Ihrem Code teilen? Es gibt viele Importoptionen, aus denen Sie auswählen können. – user1746582

+0

Hallo @Sathish Kumar, ich weiß Es ist ziemlich alt diesen Beitrag. Aber es wird wirklich hilfreich sein, wenn Sie mich mit dem gleichen Problem führen, mit dem ich konfrontiert bin. Ich bin nicht in der Lage, das öffentliche Objekt get (String name, ObjectFactory objectFactory) zu überschreiben. Ich bekomme die Methode ist öffentliche TypeVariable Suche (String-Name). Ich benutze die JSF-API Version 2.1.3. Könnten Sie mir bitte helfen? –