webentwicklung-frage-antwort-db.com.de

Stateless und Stateful Enterprise Java Beans

Ich gehe das Java EE 6-Tutorial durch und versuche, den Unterschied zwischen zustandslosen und stateful-Session-Beans zu verstehen. Wenn zustandslose Session-Beans ihren Status zwischen Methodenaufrufen nicht beibehalten, warum verhält sich mein Programm so, wie es ist?

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++;
    }
}

Der Kunde

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());
    }

}

Ich hatte erwartet, dass getNumber jedes Mal 0 zurückgibt, aber es gibt 1 zurück und das Servlet in meinem Browser wird neu geladen, um es mehr zu erhöhen. Das Problem liegt in meinem Verständnis der Funktionsweise von statuslosen Session-Beans und natürlich nicht mit den Bibliotheken oder dem Anwendungsserver. Kann mir jemand ein einfaches Hallo-Welt-Beispiel für eine zustandslose Session-Bean geben, die sich anders verhält, wenn Sie sie in stateful ändern?

87
Stanley kelly

Der wichtige Unterschied besteht nicht in privaten Member-Variablen, sondern in der Zuordnung des Status zu einem bestimmten Benutzer (denken Sie an "Einkaufswagen").

Der Stateful-Teil des Stateful-Session-Beans gleicht der Sitzung in Servlets. Stateful-Session-Beans ermöglichen es Ihrer App, diese Sitzung auch dann auszuführen, wenn kein Web-Client vorhanden ist. Wenn der App-Server eine stateless Session-Bean aus dem Objektpool abruft, weiß er, dass er verwendet werden kann, um eine beliebige Anforderung zu erfüllen, da sie keinem bestimmten Benutzer zugeordnet ist.

Eine Stateful-Session-Bean muss an den Benutzer ausgegeben werden, der sie überhaupt erst erhalten hat, da ihre Warenkorbinformationen nur ihnen bekannt sein sollten. Der App-Server sorgt dafür, dass dies der Fall ist. Stellen Sie sich vor, wie beliebt Ihre App wäre, wenn Sie mit dem Einkaufen anfangen könnten, und der App-Server hat mir dann das Stateful-Session-Bean gegeben, als ich kam.

Ihr privates Datenmitglied ist in der Tat "state", aber es ist kein "Warenkorb". Versuchen Sie, Ihr (sehr gutes) Beispiel zu wiederholen, damit die inkrementierte Variable einem bestimmten Benutzer zugeordnet wird. Erhöhen Sie ihn, erstellen Sie einen neuen Benutzer und sehen Sie, ob er den inkrementierten Wert noch sehen kann. Bei korrekter Ausführung sollte jeder Benutzer nur seine Version des Zählers sehen.

89
duffymo

Stateless Session Beans (SLSB) sind nicht gebunden an einen Client und es gibt keine Garantie, damit ein Client bei jedem Methodenaufruf dieselbe Instanz abrufen kann (einige Container können Beans mit erstellen und zerstören.) Bei jeder Methodenaufrufsitzung handelt es sich hierbei um eine implementierungsspezifische Entscheidung. Instanzen werden jedoch normalerweise in einem Pool zusammengefasst - und Cluster-Umgebungen werden nicht erwähnt. Mit anderen Worten, obwohl zustandslose Beans über Instanzvariablen verfügen können, sind diese Felder nicht für einen Client spezifisch, sodass ___ sie sich nicht zwischen Remote-Aufrufen auf sie verlassen muss. 

Im Gegensatz dazu sind Stateful Session Beans (SFSB) dediziert für einen Client für die gesamte Lebensdauer, es gibt kein Swapping oder Pooling von Instanzen (es kann nach Passivierung aus dem Speicher entfernt werden, um Ressourcen zu sparen. und Konversationszustand beibehalten. Dies bedeutet, dass die Instanzvariablen der Bean Daten zwischen Methodenaufrufen relativ zum Client halten können. Dies ermöglicht interdependente Methodenaufrufe (Änderungen, die von einer Methode vorgenommen werden, wirken sich auf nachfolgende Methodenaufrufe aus). Mehrstufige Prozesse (ein Registrierungsprozess, ein Warenkorb, ein Buchungsprozess ...) sind typische Anwendungsfälle für SFSB.

Eine Sache noch. Wenn Sie SFSB verwenden, müssen Sie müssen das Einfügen dieser Klassen vermeiden in Klassen, die in der Natur Multithreading sind, wie Servlets und JSF-verwaltete Beans (die nicht von allen Clients gemeinsam genutzt werden sollen). Wenn Sie SFSB in Ihrer Webanwendung verwenden möchten, müssen Sie eine JNDI-Suche durchführen und die zurückgegebene EJB-Instanz im Objekt HttpSession für zukünftige Aktivitäten speichern. Sowas in der Art:

try {
    InitialContext ctx = new InitialContext();
    myStateful = (MyStateful)ctx.lookup("Java:comp/env/MyStatefulBean");
    session.setAttribute("my_stateful", myStateful);
} catch (Exception e) {
    // exception handling
}
130
Pascal Thivent

Staatenlos und zustandsbehaftet bedeuten in diesem Zusammenhang nicht ganz das, was Sie erwarten könnten.

Statefulness mit EJBs bezieht sich auf das, was ich Conversational State nenne. Das klassische Beispiel ist eine Flugbuchung. Wenn es aus drei Schritten besteht:

  • Sitzplatz reservieren
  • Kreditkarte belasten
  • Ticket ausstellen

Stellen Sie sich vor, jeder davon ist ein Methodenaufruf für ein Session-Bean. Ein Stateful-Session-Bean kann diese Art von conversation beibehalten, damit es sich daran erinnert, was zwischen den Aufrufen passiert.

Zustandslose Session-Beans verfügen nicht über eine solche Kapazität für den Konversationsstatus.

Globale Variablen in einer Session-Bean (stateless oder stateful) sind etwas ganz anderes. In Stateful-Session-Beans wird ein Pool von Beans erstellt (da eine Bean nur jeweils in einer Konversation verwendet werden kann), während für zustandslose Sesion-Beans oft nur eine Instanz vorhanden ist, wodurch die globale Variable funktioniert, aber ich denke nicht das ist notwendigerweise garantiert.

16
cletus

Dies passiert, weil der Container nur eine Bean-Instanz im Pool hat, die für alle Aufrufe wiederverwendet wird. Wenn Sie die Clients parallel ausführen, wird ein anderes Ergebnis angezeigt, da der Container mehr Bean-Instanzen im Pool erstellt. 

4
Neyma

Die Hauptunterschiede zwischen den beiden Haupttypen von Session-Beans sind:

Zustandslose Bohnen

  1. Stateless Session Beans sind diejenigen, die keinen Gesprächszustand mit dem Client haben, der seine Methoden aufgerufen hat. Aus diesem Grund können sie einen Pool von Objekten erstellen, der zur Interaktion mit mehreren Clients verwendet werden kann.
  2. Statuslose Beans in Bezug auf die Leistung sind besser, da sie nicht über Zustände pro Client verfügen.
  3. Sie können mehrere Anforderungen von mehreren Clients parallel bearbeiten.

Stateful Beans

  1. Stateful-Session-Beans können den Konversationsstatus mit mehreren Clients gleichzeitig aufrechterhalten, und die Task wird nicht zwischen den Clients aufgeteilt.
  2. Nach Abschluss der Sitzung wird der Status nicht beibehalten. 
  3. Der Container kann den Status zur späteren Verwendung als stale-Status serialisieren und speichern. Dies geschieht, um Ressourcen des Anwendungsservers zu sparen und Bean-Fehler zu unterstützen. 
3
Pritam Banerjee

Es hat gute Antworten. Ich möchte eine kleine Antwort hinzufügen. Stateless Bean sollte nicht zum Speichern von Kundendaten verwendet werden. Es sollte verwendet werden, um "Aktionen oder Prozesse zu modellieren, die auf einmal ausgeführt werden können".

2
malatesh

Gute Frage, 

versuchen Sie diesen Code (ändern Sie 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

0
ZURA Tikaradze