it-swarm.com.ru

Java-бины Enterprise с сохранением состояния и состоянием

Я изучаю руководство по 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?

87
Stanley kelly

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

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

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

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

89
duffymo

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

Напротив, Stateful Session Bean (SFSB) являются выделенными для одного клиента на протяжении всей их жизни, нет замены или объединения экземпляров (его можно удалить из памяти после пассивации для экономии ресурсов, но это другая история) и поддерживать разговорное состояние. Это означает, что переменные экземпляра bean-компонента могут хранить данные относительно клиента между вызовами методов. И это позволяет иметь взаимозависимые вызовы методов (изменения, сделанные одним методом, влияют на последующие вызовы методов). Многоэтапные процессы (процесс регистрации, корзина покупок, процесс бронирования ...) являются типичными вариантами использования 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
}
130
Pascal Thivent

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

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

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

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

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

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

16
cletus

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

4
Neyma

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

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

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

Stateful Beans

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

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

2
malatesh

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

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