Я просматриваю руководство по Java EE 6 и пытаюсь понять разницу между сессионными компонентами без сохранения состояния и с сохранением состояния. Если сессионные компоненты без сохранения состояния не сохраняют свое состояние между вызовами методов, почему моя программа действует именно так?
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++;
}
}
Клиент
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());
}
}
Я ожидал, что getNumber будет возвращать 0 каждый раз, но он возвращает 1, и перезагрузки сервлета в моем браузере увеличивают его еще больше. Проблема заключается в моем понимании того, как работают сессионные компоненты без сохранения состояния, а не в библиотеках или сервере приложений, конечно. Может ли кто-нибудь дать мне простой пример типа hello world сеансового bean-компонента без сохранения состояния, который ведет себя по-другому, когда вы меняете его на состояние с сохранением состояния?
источник
Ответы:
Важное различие заключается не в частных переменных-членах, а в связывании состояния с конкретным пользователем (подумайте о «корзине покупок»).
Фрагмент сессионного компонента с отслеживанием состояния похож на сеанс в сервлетах. Сессионные компоненты с отслеживанием состояния позволяют вашему приложению продолжать этот сеанс, даже если нет веб-клиента. Когда сервер приложений извлекает сеансовый компонент без сохранения состояния из пула объектов, он знает, что его можно использовать для удовлетворения ЛЮБОГО запроса, поскольку он не связан с конкретным пользователем.
Сессионный компонент с сохранением состояния должен быть выдан пользователю, который его получил, потому что информация об их корзине покупок должна быть известна только им. Сервер приложений гарантирует, что это так. Представьте, насколько популярным было бы ваше приложение, если бы вы могли начать делать покупки, а затем сервер приложений предоставил мне ваш сессионный компонент с отслеживанием состояния, когда я пришел!
Таким образом, ваш частный элемент данных действительно является «государственным», но это не «корзина для покупок». Попробуйте повторить свой (очень хороший) пример, чтобы увеличиваемая переменная была связана с конкретным пользователем. Увеличьте его, создайте нового пользователя и посмотрите, могут ли они по-прежнему видеть увеличенное значение. Если все сделано правильно, каждый пользователь должен видеть только свою версию счетчика.
источник
Сессионные компоненты без сохранения состояния (SLSB) не привязаны к одному клиенту, и нет гарантии, что один клиент получит один и тот же экземпляр при каждом вызове метода (некоторые контейнеры могут создавать и уничтожать компоненты при каждом сеансе вызова метода, это решение зависит от реализации. , но экземпляры обычно объединяются в пулы - и я не упоминаю кластерные среды). Другими словами, хотя bean-компоненты без состояния могут иметь переменные экземпляра, эти поля не относятся к одному клиенту, поэтому не полагайтесь на них между удаленными вызовами.
Напротив, сеансовые компоненты с отслеживанием состояния (SFSB) предназначены для одного клиента на протяжении всей их жизни, нет обмена или объединения экземпляров (они могут быть удалены из памяти после пассивации для экономии ресурсов, но это уже другая история) и поддерживают диалоговое состояние . Это означает, что переменные экземпляра bean-компонента могут хранить данные относительно клиента между вызовами методов. И это позволяет иметь взаимозависимые вызовы методов (изменения, внесенные одним методом, влияют на последующие вызовы методов). Многоступенчатые процессы (процесс регистрации, корзина покупок, процесс бронирования ...) являются типичными вариантами использования SFSB.
Еще кое-что. Если вы используете SFSB, вы должны избегать их внедрения в классы, которые по своей природе многопоточные, такие как сервлеты и управляемые компоненты JSF (вы не хотите, чтобы они были общими для всех клиентов). Если вы хотите использовать SFSB в своем веб-приложении, вам необходимо выполнить поиск JNDI и сохранить возвращенный экземпляр EJB в
HttpSession
объекте для будущих действий. Что-то такое:try { InitialContext ctx = new InitialContext(); myStateful = (MyStateful)ctx.lookup("java:comp/env/MyStatefulBean"); session.setAttribute("my_stateful", myStateful); } catch (Exception e) { // exception handling }
источник
Без сохранения состояния и с сохранением состояния в этом контексте не совсем то, чего вы могли ожидать.
Состояние с EJB относится к тому, что я называю диалоговым состоянием . Классический пример - бронирование авиабилетов. Если он состоит из трех шагов:
Представьте, что каждый из них является вызовом метода сеансового компонента. Сессионный компонент с отслеживанием состояния может поддерживать такой диалог, чтобы запоминать, что происходит между вызовами.
Сессионные компоненты без сохранения состояния не имеют такой возможности для разговорного состояния.
Глобальные переменные внутри сессионного компонента (без состояния или с сохранением состояния) - это нечто совершенно иное. Сессионные бины с сохранением состояния будут иметь пул бинов (поскольку бин может использоваться только в одном диалоге за раз), тогда как сеансные бины без сохранения состояния часто будут иметь только один экземпляр, что заставит глобальную переменную работать, но я не думаю это обязательно гарантировано.
источник
Хороший вопрос,
попробуйте этот код (измените 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++; } }
Сервлет_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()); } }
Сервлет_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 - @ без сохранения состояния
http: // локальный: 8080 / MYServletDemo / ServletClient
1
http: // локальный: 8080 / MYServletDemo / ServletClient
2
http: // локальный: 8080 / MYServletDemo_war_exploded / newServletClient
3
http: // локальный: 8080 / MYServletDemo / ServletClient
4
case: MyBean - @ Stateful
http: // локальный: 8080 / MYServletDemo / ServletClient
1
http: // локальный: 8080 / MYServletDemo / ServletClient
2
http: // локальный: 8080 / MYServletDemo / newServletClient
1
http: // локальный: 8080 / MYServletDemo / ServletClient
3
источник
Основные различия между двумя основными типами сессионных компонентов:
Бобы без сохранения состояния
Бобы с отслеживанием состояния
источник
Это происходит потому, что контейнер имеет только один экземпляр компонента в пуле, который повторно используется для всех вызовов. Если вы запустите клиентов параллельно, вы увидите другой результат, потому что контейнер создаст больше экземпляров bean-компонентов в пуле.
источник
На него есть хорошие ответы. Хочу добавить небольшой ответ. Бин без сохранения состояния не должен использоваться для хранения каких-либо клиентских данных. Его следует использовать для «моделирования действий или процессов, которые можно выполнить за один раз».
источник