Stateless 및 Stateful Enterprise Java Bean


93

Java EE 6 튜토리얼을 진행 중이며 Stateless와 Stateful 세션 Bean의 차이점을 이해하려고합니다. Stateless Session Bean이 메소드 호출 사이에 상태를 유지하지 않는 경우 내 프로그램이 그대로 작동하는 이유는 무엇입니까?

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로 변경할 때 다르게 동작하는 stateless 세션 빈의 간단한 hello world 유형 예제를 줄 수 있습니까?


6
관련 : stackoverflow.com/questions/8887140/… 이 답변은 이해하기 더 간단 할 수 있습니다. 서블릿은 기본적으로 애플리케이션 범위입니다 (모든 HTTP 요청 / 세션에서 공유 / 재사용되는 애플리케이션 전체에 서블릿 인스턴스가 1 개뿐입니다.
BalusC

당신은 0의 값을 기대하지 수 안녕하세요, 당신은 .... 첫번째 증가를 수행 한 후 값을 얻을
rzur2004

질문 해 주셔서 감사합니다. 현재 내 문제를 해결합니다. 나는 더 나은 질문 수 없었다
kholofelo MALOMA을

답변:


93

중요한 차이점은 개인 멤버 변수가 아니라 상태를 특정 사용자와 연관시키는 것입니다 (예 : "장바구니").

Stateful Session Bean의 Stateful 부분은 서블릿의 세션과 같습니다. Stateful 세션 Bean을 사용하면 웹 클라이언트가없는 경우에도 앱이 해당 세션을 유지할 수 있습니다. 앱 서버가 개체 풀에서 상태 비 저장 세션 빈을 가져올 때 특정 사용자와 연결되어 있지 않기 때문에 모든 요청을 충족시키는 데 사용할 수 있음을 알고 있습니다.

상태 저장 세션 빈은 쇼핑 카트 정보가 그들에게만 알려 져야하기 때문에 처음에 그것을 얻은 사용자에게 할당되어야합니다. 앱 서버는이를 확인합니다. 쇼핑을 시작할 수 있고 내가 왔을 때 앱 서버가 Stateful 세션 빈을 주었다면 앱이 얼마나 인기가 있을지 상상해보세요!

따라서 귀하의 개인 데이터 구성원은 실제로 "상태"이지만 "장바구니"는 아닙니다. 증분 변수가 특정 사용자와 연관되도록 (매우 좋은) 예제를 다시 실행하십시오. 그것을 증가시키고, 새로운 사용자를 생성하고, 그들이 증가 된 값을 여전히 볼 수 있는지 확인하십시오. 올바르게 수행되면 모든 사용자는 자신의 카운터 버전 만 볼 수 있습니다.


의견에 명시적인 답변을 제공 할 수 있습니까? 이 예제에서 항상 Stateless Bean이 값을 보유하고 매번 증가하는 이유는 무엇입니까? 사용자가 한 명뿐이기 때문에?
arjacsoh

2
카운터는 사용자 수에 관계없이 증가합니다. 따라서 user1이 들어 와서 카운터를 1로 증가시키고 동시에 user2가 들어 와서이를 증가 시키면 값은 2가됩니다. 실제로 user1이 1을 가지고 있고 user2가 1을 가지고 있음을 보여야합니다. 위의 예).
Krishna

137

Stateless Session Beans (SLSB)는 하나의 클라이언트에 묶여 있지 않으며 한 클라이언트가 각 메소드 호출에 대해 동일한 인스턴스를 얻을 수 있다는 보장없습니다 (일부 컨테이너는 각 메소드 호출 세션에서 Bean을 생성하고 파괴 할 수 있습니다. 이는 구현 별 결정입니다.) ,하지만 인스턴스는 일반적으로 풀링되며 클러스터링 된 환경은 언급하지 않습니다.) 즉, stateless bean이 인스턴스 변수를 가질 수 있지만 이러한 필드는 한 클라이언트에만 국한되지 않으므로 원격 호출 사이에 이들 필드에 의존하지 마십시오.

대조적으로, Stateful Session Beans (SFSB)는 전체 수명 동안 하나의 클라이언트 전용 이며, 인스턴스의 스와핑이나 풀링이 없습니다 (자원을 절약하기 위해 패시베이션 후에 메모리에서 제거 될 수 있지만 이는 또 다른 이야기입니다) . 대화 상태를 유지합니다 . 이것은 빈의 인스턴스 변수가 메소드 호출 사이에 클라이언트에 상대적인 데이터를 유지할 수 있음을 의미합니다. 그리고 이것은 상호 의존적 인 메서드 호출을 가능하게합니다 (한 메서드에 의한 변경은 후속 메서드 호출에 영향을 미칩니다). 다단계 프로세스 (등록 프로세스, 쇼핑 카트, 예약 프로세스 ...)는 SFSB의 일반적인 사용 사례입니다.

하나 더. SFSB를 사용하는 경우 Servlet 및 JSF 관리 Bean과 같이 본질적으로 다중 스레드 인 클래스에 SFSB를 삽입 하지 않아야합니다 (모든 클라이언트에서 공유하는 것을 원하지 않음). 웹 애플리케이션에서 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
}

정리 해주셔서 감사합니다. 클라이언트에 대해 독립 실행 형 명령 줄 프로그램을 사용하면 그 차이를 분명히 알 수 있습니다.
Stanley kelly

당신의 의견에 감사드립니다, 그들은 더 깨달았습니다. 먼저 추상적 인 정의를 제공 한 다음 각 상황에 대한 몇 가지 사용 사례를 지정한 다음 몇 가지 함정을 지적하십시오. Great +1
arthur 2012-06-19

합니까 피할 주입 부분이 아니라 EJB 3.1 나간다?
jacktrades

7
@Pascal "Stateful Session Beans (SFSB)가 평생 동안 하나의 클라이언트 전용"이라면이 기능이 SFSB에 내장되어있는 것입니다. 그러면 왜 HttpSession 객체에 저장해야합니까?
user1169587

2
이미 '세션'된 경우 세션에 상태 저장 빈이 필요한 이유는 무엇입니까? 이렇게하면 모든 객체를 세션화할 수 있습니다. 설명 pls
Georgy Gobozov 2013

18

이 맥락에서 Stateless와 Stateful은 기대하는 바를 의미하지 않습니다.

EJB를 사용한 Statefulness는 내가 대화 형 상태 라고 부르는 것을 말합니다 . 전형적인 예는 항공편 예약입니다. 세 단계로 구성된 경우 :

  • 좌석 예약
  • 신용 카드 청구
  • 티켓 발급

각각이 세션 빈에 대한 메서드 호출이라고 상상해보십시오. Stateful Session Bean은 이러한 종류의 대화를 유지할 수 있으므로 호출 사이에 일어나는 일을 기억합니다.

Stateless 세션 Bean에는 대화 상태에 대한 용량이 없습니다.

세션 빈 (상태 비 저장 또는 상태 저장) 내부의 전역 변수는 완전히 다른 것입니다. Stateful 세션 빈은 생성 된 빈 풀을 가지지 만 (빈은 한 번에 하나의 대화에서만 사용할 수 있기 때문에) 상태 비 저장 세션 빈은 종종 하나의 인스턴스 만 가지므로 전역 변수가 작동하지만 저는 생각하지 않습니다 이것은 반드시 보장됩니다.


5

두 가지 주요 세션 Bean 유형 간의 주요 차이점 은 다음과 같습니다.

Stateless Bean

  1. Stateless Session Bean 은 메소드를 호출 한 클라이언트와 대화 상태 가 없는 것입니다 . 이러한 이유로 여러 클라이언트 와 상호 작용하는 데 사용할 수있는 개체 풀을 만들 수 있습니다 .
  2. 성능이 현명한 상태 비 저장 빈은 클라이언트 당 상태 가 없기 때문에 더 좋습니다 .
  3. 여러 클라이언트의 여러 요청을 병렬로 처리 수 있습니다 .

상태 저장 빈

  1. Stateful Session Bean은 한 번에 여러 클라이언트와 대화 상태를 유지할 수 있으며 클라이언트간에 작업이 공유되지 않습니다.
  2. 세션이 완료된 후에는 상태 유지 되지 않습니다 .
  3. 컨테이너는 나중에 사용할 수 있도록 상태오래된 상태 로 직렬화하고 저장할 수 있습니다. 이는 애플리케이션 서버의 자원을 절약하고 Bean 실패를 지원하기 위해 수행됩니다.

4

컨테이너에는 모든 호출에 재사용되는 풀에 빈 인스턴스가 하나만 있기 때문에 이런 일이 발생합니다. 클라이언트를 병렬로 실행하면 컨테이너가 풀에 더 많은 빈 인스턴스를 생성하기 때문에 다른 결과가 표시됩니다.


4

좋은 답변이 있습니다. 작은 답변을 추가하고 싶습니다. Stateless Bean은 클라이언트 데이터를 보관하는 데 사용해서는 안됩니다. "한 번에 수행 할 수있는 작업 또는 프로세스를 모델링"하는 데 사용해야합니다.


4

좋은 질문,

이 코드를 시도해보십시오 (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());
    }

}

사례 : MyBean-@ Stateless

http : // localhost : 8080 / MYServletDemo / ServletClient

1

http : // localhost : 8080 / MYServletDemo / ServletClient

2

http : // localhost : 8080 / MYServletDemo_war_exploded / newServletClient

http : // localhost : 8080 / MYServletDemo / ServletClient

4

사례 : 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


1
예, 그게 다이고 작동합니다! 아주 쉬운 설명, 감사합니다!
Nesquik27
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.