Je suis en train de suivre le didacticiel Java EE 6 et j'essaie de comprendre la différence entre les beans de session sans état et avec état. Si les beans session sans état ne conservent pas leur état entre les appels de méthode, pourquoi mon programme agit-il comme il est?
package mybeans;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
@LocalBean
@Stateless
public class MyBean {
private int number = 0;
public int getNumber() {
return number;
}
public void increment() {
this.number++;
}
}
Le client
import Java.io.IOException;
import javax.ejb.EJB;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
import mybeans.MyBean;
import Java.io.PrintWriter;
@WebServlet(name = "ServletClient", urlPatterns = { "/ServletClient" })
public class ServletClient extends HttpServlet {
private static final long serialVersionUID = 1L;
@EJB
MyBean mybean;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
mybean.increment();
out.println(mybean.getNumber());
}
}
Je m'attendais à ce que getNumber renvoie 0 à chaque fois, mais il renvoie 1 et les rechargements de la servlet dans mon navigateur l’augmentent davantage. Le problème vient de ma compréhension du fonctionnement des beans de session sans état et non pas des bibliothèques ou du serveur d'applications, bien sûr. Quelqu'un peut-il me donner un exemple simple, de type hello world, d'un bean de session sans état qui se comporte différemment lorsque vous le changez en stateful?
La différence importante n'est pas les variables des membres privés, mais l'association d'un état à un utilisateur particulier (pensez au "panier").
Le bean stateful de session stateful ressemble à la session dans les servlets. Les beans de session avec état permettent à votre application d'avoir toujours cette session même s'il n'y a pas de client Web. Lorsque le serveur d'application extrait un bean de session sans état du pool d'objets, il sait qu'il peut être utilisé pour satisfaire toute requête, car elle n'est pas associée à un utilisateur particulier.
Un haricot de session avec état doit être distribué à l'utilisateur qui l'a obtenu en premier lieu, car les informations relatives à leur panier d'achat ne doivent être connues que de lui. Le serveur d'applications s'assure que c'est bien le cas. Imaginez à quel point votre application serait populaire si vous pouviez commencer à magasiner, puis le serveur de l'application m'a donné votre bean stateful de session lorsque je suis arrivé!
Donc, votre membre de données privé est bien "état", mais ce n'est pas "panier". Essayez de refaire votre (très bon) exemple pour que la variable incrémentée soit associée à un utilisateur particulier. Incrémentez-le, créez un nouvel utilisateur et voyez s'il peut toujours voir la valeur incrémentée. Si cela est fait correctement, chaque utilisateur ne devrait voir que sa version du compteur.
Stateless Session Beans (SLSB) sont non liés à un client et il y a aucune garantie pour qu'un client obtienne la même instance à chaque invocation de méthode (certains conteneurs peuvent créer et détruire des beans avec chaque session d’appel de méthode, il s’agit d’une décision spécifique à l’implémentation, mais les instances sont généralement mises en pool (et je ne mentionne pas les environnements en cluster). En d'autres termes, bien que les beans sans état puissent avoir des variables d'instance, ces champs ne sont pas spécifiques à un client. Par conséquent, Ne les utilise pas entre les appels distants.
En revanche, les Stateful Session Beans (SFSB) sont dédiés à un client toute leur vie, il n'y a pas d'échange ni de regroupement d'instances (il peut être supprimé de la mémoire après la passivation pour économiser des ressources, mais c'est une autre histoire) et maintenir l'état conversationnel. Cela signifie que les variables d'instance du bean peuvent conserver des données relatives au client entre les invocations de méthodes. Et cela permet d’avoir des appels de méthode interdépendants (les modifications apportées par une méthode affectent les appels de méthode suivants). Les processus en plusieurs étapes (un processus d'inscription, un panier d'achat, un processus de réservation, etc.) sont des cas d'utilisation typiques pour SFSB.
Une dernière chose. Si vous utilisez SFSB, vous (vous devez éviter de les injecter} dans des classes à plusieurs ressources, telles que les servlets et les beans gérés JSF (vous ne voulez pas que tous les clients la partagent). Si vous souhaitez utiliser SFSB dans votre application Web, vous devez effectuer une recherche JNDI et stocker l'instance EJB renvoyée dans l'objet HttpSession
pour une activité future. Quelque chose comme ca:
try {
InitialContext ctx = new InitialContext();
myStateful = (MyStateful)ctx.lookup("Java:comp/env/MyStatefulBean");
session.setAttribute("my_stateful", myStateful);
} catch (Exception e) {
// exception handling
}
Dans ce contexte, sans état et sans état ne signifie pas exactement ce à quoi vous pouvez vous attendre.
L'état dynamique avec les EJB fait référence à ce que j'appelle état conversationnel. L'exemple classique est une réservation de vol. S'il se compose de trois étapes:
Imaginez que chacun d’eux soit un appel de méthode à un bean de session. Un bean session avec état peut maintenir ce type de conversation afin qu'il se souvienne de ce qui se passe entre les appels.
Les beans session sans état n'ont pas cette capacité pour l'état conversationnel.
Les variables globales à l'intérieur d'un bean de session (sans état ou avec état) sont complètement différentes. Un pool de haricots sera créé dans les beans de session avec état (puisqu'un bean ne peut être utilisé que dans une conversation à la fois), alors que les beans sans état n'ont souvent qu'un seul exemple, ce qui fera que la variable globale fonctionne c'est forcément garanti.
Cela se produit parce que le conteneur n'a qu'une seule instance de bean dans le pool qui est réutilisée pour tous les appels. Si vous exécutez les clients en parallèle, vous obtiendrez un résultat différent car le conteneur créera plus d'instances de beans dans le pool.
Les principales différences entre les deux principaux types de beans de session sont les suivantes:
Haricots Apatrides
Stateful Beans
Il a de bonnes réponses. Je voudrais ajouter une petite réponse. Stateless Bean ne doit pas contenir de données client. Il devrait être utilisé pour "modéliser les actions ou les processus pouvant être réalisés en une fois".
Bonne question,
essayez ce code (changez MyBean Stateful/Stateless.):
import javax.ejb.LocalBean;
import javax.ejb.Stateful;
import javax.ejb.Stateless;
@LocalBean
@Stateless
public class MyBean {
private int number = 0;
public int getNumber() {
return number;
}
public void increment() {
this.number++;
}
}
Servlet_1
import Java.io.IOException;
import javax.ejb.EJB;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
import Java.io.PrintWriter;
@WebServlet(name = "ServletClient", urlPatterns = { "/ServletClient" })
public class ServletClient extends HttpServlet {
private static final long serialVersionUID = 1L;
@EJB
MyBean mybean;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
mybean.increment();
out.println(mybean.getNumber());
}
}
Servlet_2
import Java.io.IOException;
import javax.ejb.EJB;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
import Java.io.PrintWriter;
@WebServlet(name = "NewServletClient", urlPatterns = { "/NewServletClient" })
public class NewServletClient extends HttpServlet {
private static final long serialVersionUID = 1L;
@EJB
MyBean mybean;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
mybean.increment();
out.println(mybean.getNumber());
}
}
case: MyBean - @ Stateless
http: // localhost: 8080/MYServletDemo/ServletClient
1
http: // localhost: 8080/MYServletDemo/ServletClient
2
http: // localhost: 8080/MYServletDemo_war_exploded/newServletClient
3
http: // localhost: 8080/MYServletDemo/ServletClient
4
case: MyBean - @ Stateful
http: // localhost: 8080/MYServletDemo/ServletClient
1
http: // localhost: 8080/MYServletDemo/ServletClient
2
http: // localhost: 8080/MYServletDemo/newServletClient
1
http: // localhost: 8080/MYServletDemo/ServletClient
3