Przechodzę przez samouczek Java EE 6 i próbuję zrozumieć różnicę między fasolami sesji bezstanowych i stanowymi. Jeśli bezstanowe ziarna sesji nie zachowują swojego stanu między wywołaniami metod, dlaczego mój program zachowuje się tak, jak jest?
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++;
}
}
Klient
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());
}
}
Spodziewałem się, że getNumber zwróci 0 za każdym razem, ale zwraca 1, a przeładowania serwletu w mojej przeglądarce zwiększają go bardziej. Problem polega na tym, że rozumiem, jak działają bezstanowe komponenty bean sesji, a nie oczywiście z bibliotekami lub serwerem aplikacji. Czy ktoś może mi podać prosty przykład hello world typu bean bezstanowej sesji, który zachowuje się inaczej po zmianie na stanowy?
java
jakarta-ee
ejb
ejb-3.1
stateful-session-bean
Stanley Kelly
źródło
źródło
Odpowiedzi:
Istotną różnicą nie są prywatne zmienne składowe, ale powiązanie stanu z konkretnym użytkownikiem (pomyśl „koszyk”).
Stanowy element stanowego komponentu bean sesji jest podobny do sesji w serwletach. Stanowe komponenty bean sesji umożliwiają aplikacji zachowanie tej sesji, nawet jeśli nie ma klienta WWW. Gdy serwer aplikacji pobiera bezstanowy komponent bean sesji z puli obiektów, wie, że można go użyć do spełnienia DOWOLNEGO żądania, ponieważ nie jest on skojarzony z określonym użytkownikiem.
Stanowy bean sesji musi zostać przekazany użytkownikowi, który go dostał, ponieważ informacje o jego koszyku powinny być znane tylko jemu. Serwer aplikacji zapewnia, że tak jest. Wyobraź sobie, jak popularna byłaby Twoja aplikacja, gdybyś mógł zacząć robić zakupy, a serwer aplikacji przekazał mi Twój stanowy bean sesji, kiedy się pojawiłem!
Więc twój prywatny członek danych jest rzeczywiście „stan”, ale nie jest to „koszyk”. Spróbuj powtórzyć (bardzo dobry) przykład, tak aby zmienna inkrementowana była powiązana z konkretnym użytkownikiem. Zwiększ go, utwórz nowego użytkownika i sprawdź, czy nadal widzą zwiększoną wartość. Jeśli zrobisz to poprawnie, każdy użytkownik powinien zobaczyć tylko swoją wersję licznika.
źródło
Bezstanowe komponenty bean sesji (SLSB) nie są powiązane z jednym klientem i nie ma gwarancji, że jeden klient otrzyma tę samą instancję przy każdym wywołaniu metody (niektóre kontenery mogą tworzyć i niszczyć komponenty bean przy każdej sesji wywołania metody, jest to decyzja specyficzna dla implementacji , ale instancje są zwykle łączone - i nie wspominam o środowiskach klastrowych). Innymi słowy, chociaż bezstanowe komponenty bean mogą mieć zmienne instancji, pola te nie są specyficzne dla jednego klienta, więc nie należy na nich polegać między zdalnymi wywołaniami.
W przeciwieństwie do tego Stateful Session Beans (SFSB) są dedykowane jednemu klientowi przez całe życie, nie ma zamiany ani gromadzenia instancji (może zostać usunięty z pamięci po pasywacji, aby zaoszczędzić zasoby, ale to już inna historia) i utrzymać stan konwersacji . Oznacza to, że zmienne instancji komponentu bean mogą przechowywać dane względem klienta między wywołaniami metod. Dzięki temu możliwe są współzależne wywołania metod (zmiany dokonane przez jedną metodę wpływają na kolejne wywołania metod). Procesy wieloetapowe (rejestracja, koszyk, proces rezerwacji ...) to typowe przypadki użycia SFSB.
Jeszcze jedna rzecz. Jeśli używasz SFSB, musisz unikać wstrzykiwania ich do klas, które są z natury wielowątkowe, takich jak serwlety i komponenty bean zarządzane przez JSF (nie chcesz, aby były one udostępniane wszystkim klientom). Jeśli chcesz używać SFSB w swojej aplikacji internetowej, musisz przeprowadzić wyszukiwanie JNDI i zapisać zwróconą instancję EJB w
HttpSession
obiekcie na potrzeby przyszłych działań. Coś w tym stylu:try { InitialContext ctx = new InitialContext(); myStateful = (MyStateful)ctx.lookup("java:comp/env/MyStatefulBean"); session.setAttribute("my_stateful", myStateful); } catch (Exception e) { // exception handling }
źródło
Bezpaństwowość i stan w tym kontekście nie oznaczają do końca tego, czego można by się spodziewać.
Stanowość z EJB odnosi się do tego, co nazywam stanem konwersacyjnym . Klasycznym przykładem jest rezerwacja lotu. Jeśli składa się z trzech kroków:
Wyobraź sobie, że każdy z nich jest wywołaniem metody do komponentu bean sesji. Stanowy bean sesji może podtrzymywać tego rodzaju konwersację, aby pamiętać, co dzieje się między połączeniami.
Bezstanowe ziarna sesji nie mają takiej zdolności do tworzenia stanu konwersacyjnego.
Zmienne globalne wewnątrz komponentu bean sesji (bezstanowe lub stanowe) to coś zupełnie innego. Stanowe ziarna sesji będą miały utworzoną pulę fasoli (ponieważ fasola może być używana tylko w jednej rozmowie naraz), podczas gdy bezstanowe ziarna sesji będą często miały tylko jedną instancję, co spowoduje, że zmienna globalna będzie działać, ale nie sądzę jest to koniecznie zagwarantowane.
źródło
Dobre pytanie,
wypróbuj ten kod (zmień 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
źródło
Główne różnice między dwoma głównymi typami ziaren sesyjnych to:
Fasola bezpaństwowa
Stateful Beans
źródło
Dzieje się tak, ponieważ kontener ma tylko jedną instancję komponentu bean w puli, która jest ponownie używana dla wszystkich wywołań. Jeśli uruchomisz klientów równolegle, zobaczysz inny wynik, ponieważ kontener utworzy więcej instancji bean w puli.
źródło
Ma dobre odpowiedzi. Chciałbym dodać małą odpowiedź. Bezstanowy komponent Bean nie powinien przechowywać żadnych danych klienta. Powinien służyć do „modelowania działań lub procesów, które można wykonać za jednym zamachem”.
źródło