Nel nostro JavaEE6 progetto (EJB3, JSF2) su JBoss 7.1.1, sembra che abbiamo una perdita di memoria con SeamFaces @ViewScoped
.Perdita di memoria con bean ViewScoped?
Abbiamo fatto un po 'il prototipo per verificare il fatto:
- usiamo JMeter per chiamare una pagina di 200 volte;
- la pagina contiene e chiama un bean a pila di viste che inietta un EJB con stato;
- fissiamo il timeout della sessione a 1 minuto.
Alla fine del test, controlliamo il contenuto della memoria con VisualVM, ed ecco quello che abbiamo ottenuto:
- con un fagiolo
@ViewScoped
, ancora otteniamo 200 istanze del statefulMyController
- e il metodo@PreDestroy
non viene mai chiamato; - con un bean
@ConversationScoped
, il metodo@preDestroy
si chiama un fine sessione e quindi abbiamo una memoria pulita.
Usiamo male l'ambito di visualizzazione o è davvero un bug?
Ecco la pagina XHTML:
<!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>
Ora il fagiolo incluso myBean
. Per la variante @ConversationScoped
, tutte le parti commentate non sono commentate.
@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;
}
}
E poi il fagiolo stateful iniettato MyController
:
@Stateful
@LocalBean
public class MyController
{
public void call()
{
System.out.println("call ");
}
@PreDestroy
public void destroy()
{
System.out.println("Destroy");
}
}
Abbiamo provato con CODI e il test è andato bene. Bello! –