Java-бины Enterprise с сохранением состояния и состоянием - PullRequest
88 голосов
/ 28 февраля 2010

Я изучаю руководство по 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, и перезагрузки сервлета в моем браузере увеличивают его больше. Проблема в том, что я понимаю, как работают сессионные компоненты без сохранения состояния, а не с библиотеками или сервером приложений. Может ли кто-нибудь дать мне простой пример типа «Привет, мир» сессионного компонента без сохранения состояния, который ведет себя по-разному, когда вы меняете его на Stateful?

Ответы [ 7 ]

131 голосов
/ 28 февраля 2010

Сессионные компоненты без состояния (SLSB) не привязаны к одному клиенту, и нет гарантии для одного клиента, чтобы он получал один и тот же экземпляр при каждом вызове метода (некоторые контейнеры могут создавать и уничтожать bean-компоненты при каждом сеансе вызова метода, это решение, зависящее от реализации, но экземпляры обычно объединяются в пул (и я не упоминаю кластерные среды). Другими словами, хотя bean-компоненты без сохранения состояния могут иметь переменные экземпляра, эти поля не являются специфичными для одного клиента, поэтому не полагайтесь на них между удаленными вызовами.

Напротив, Stateful Session Bean (SFSB) выделен одному клиенту за всю их жизнь, нет обмена или объединения экземпляров (его можно удалить из памяти после пассивации для экономии ресурсов, но это другая история) и поддерживать разговорное состояние . Это означает, что переменные экземпляра компонента могут хранить данные относительно клиента между вызовами методов. И это позволяет иметь взаимозависимые вызовы методов (изменения, сделанные одним методом, влияют на последующие вызовы методов). Многоэтапные процессы (процесс регистрации, корзина покупок, процесс бронирования ...) являются типичными сценариями использования SFSB.

Еще одна вещь. Если вы используете SFSB, вы должны избегать внедрения их в многопоточные классы, такие как Servlets и управляемые bean-компоненты 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
}
89 голосов
/ 28 февраля 2010

Важным отличием является не закрытые переменные-члены, а связь состояния с конкретным пользователем (например, «корзина»).

Часть с сохраняющим состояние компонентом сессионного компонента похожа на сессию в сервлетах.Сессионные компоненты с сохранением состояния позволяют вашему приложению продолжать этот сеанс, даже если веб-клиент отсутствует.Когда сервер приложений выбирает сессионный компонент без сохранения состояния из пула объектов, он знает, что его можно использовать для удовлетворения ЛЮБОГО запроса, поскольку он не связан с конкретным пользователем.

Сессионный компонент с состоянием должен быть распределендля пользователя, который получил его в первую очередь, потому что информация об их корзине должна быть известна только им.Сервер приложений гарантирует, что это так.Представьте себе, насколько популярным было бы ваше приложение, если бы вы могли начать делать покупки, а затем сервер приложений дал мне ваш сессионный компонент с состоянием, когда я пришел вместе!

Таким образом, ваш личный элемент данных действительно "состояние", но это не "корзина".Попробуйте повторить ваш (очень хороший) пример, чтобы сделать так, чтобы увеличенная переменная ассоциировалась с конкретным пользователем.Увеличьте его, создайте нового пользователя и посмотрите, смогут ли они увидеть увеличенное значение.Если все сделано правильно, каждый пользователь должен видеть только свою версию счетчика.

17 голосов
/ 28 февраля 2010

В этом контексте лица без состояния и состояния не означают совсем то, что вы могли бы ожидать.

Statefulness с EJBs относится к тому, что я называю диалоговое состояние . Классический пример - бронирование авиабилетов. Если он состоит из трех шагов:

  • Резервное место
  • Платежная кредитная карта
  • Билет на выдачу

Представьте, что каждый из них является вызовом метода для сессионного компонента. Сессионный компонент с состоянием может поддерживать этот тип разговора , поэтому он запоминает, что происходит между вызовами.

Сессионные компоненты без сохранения состояния не имеют такой возможности для диалогового состояния.

Глобальные переменные внутри сессионного компонента (без состояния или с состоянием) - это нечто совершенно другое. Сессионным компонентам с сохранением состояния будет создан пул компонентов (поскольку компонент может использоваться только в одном диалоге за раз), в то время как компоненты тестирования с состоянием без состояния часто имеют только один экземпляр, что заставит работать глобальную переменную, но я не думаю, что это обязательно гарантировано.

4 голосов
/ 29 мая 2013

Это происходит потому, что у контейнера есть только один экземпляр компонента в пуле, который повторно используется для всех вызовов. Если вы запустите клиенты параллельно, вы увидите другой результат, потому что контейнер создаст больше экземпляров бинов в пуле.

3 голосов
/ 20 февраля 2017

Основные различия между двумя основными типами сессионных компонентов:

Бобы без гражданства

  1. Сессионные компоненты без сохранения состояния - это те, которые не имеют диалогового состояния с клиентом, который вызвал его методы. По этой причине они могут создавать пул объектов, которые можно использовать для взаимодействия с несколькими клиентами.
  2. Производительность в отношении bean-компонентов без сохранения состояния лучше, поскольку у них нет состояний для каждого клиента.
  3. Они могут обрабатывать несколько запросов от нескольких клиентов параллельно.

Stateful Beans

  1. Сессионные компоненты с сохранением состояния могут поддерживать диалоговое состояние одновременно с несколькими клиентами, и задача не распределяется между клиентами.
  2. После завершения сеанса состояние не сохраняется.
  3. Контейнер может сериализовать и сохранять состояние как устаревшее состояние для будущего использования. Это сделано для экономии ресурсов сервера приложений и для поддержки сбоев компонентов.
2 голосов
/ 23 октября 2018

Хороший вопрос,

попробуйте этот код (измените 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());
        }

    }

Сервлет_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

2 голосов
/ 27 марта 2016

У него хорошие ответы. Я хотел бы добавить небольшой ответ. Bean без сохранения состояния не должен использоваться для хранения данных клиента. Его следует использовать для «моделирования действий или процессов, которые можно выполнить за один раз».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...