98

Java EE 6チュートリアルを実行していて、ステートレスセッションBeanとステートフルセッションBeanの違いを理解しようとしています。ステートレスセッション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を返し、ブラウザでサーブレットをリロードするとさらに増加し​​ます。問題は、ステートレスセッションBeanがどのように機能するかを理解していることであり、もちろん、ライブラリやアプリケーションサーバーでは機能しません。ステートレスに変更すると動作が異なるステートレスセッションBeanの簡単なHelloWorldタイプの例を誰かに教えてもらえますか?

4

7 に答える 7

138

ステートレスセッションBean(SLSB)は1つのクライアントに関連付けられておらず、1つのクライアントが各メソッド呼び出しで同じインスタンスを取得する保証はありません(一部のコンテナーは、各メソッド呼び出しセッションでBeanを作成および破棄する場合があります。これは、実装固有の決定です。 、ただし、インスタンスは通常プールされます-クラスター化された環境については触れません)。つまり、ステートレスBeanにはインスタンス変数が含まれている場合がありますが、これらのフィールドは1つのクライアントに固有のものではないため、リモート呼び出し間でこれらのフィールドに依存しないでください。

対照的に、ステートフルセッションBean(SFSB)は、生涯にわたって1つのクライアント専用であり、インスタンスのスワッピングやプールはなく(リソースを節約するためにパッシベーション後にメモリから削除される場合がありますが、それは別の話です)、会話状態を維持します。これは、Beanのインスタンス変数が、メソッド呼び出し間でクライアントに関連するデータを保持できることを意味します。また、これにより、相互に依存するメソッド呼び出しを行うことができます(1つのメソッドによって行われた変更は、後続のメソッド呼び出しに影響します)。マルチステッププロセス(登録プロセス、ショッピングカート、予約プロセスなど)は、SFSBの一般的な使用例です。

もう一つ。SFSBを使用している場合は、サーブレットやJSFマネージドBeanなどのマルチスレッドのクラスにSFSBを挿入しないようにする必要があります(すべてのクライアントで共有されたくない場合)。Webアプリケーションで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
}
于 2010-02-28T15:21:30.623 に答える
97

重要な違いは、プライベートメンバー変数ではなく、状態を特定のユーザーに関連付けることです(「ショッピングカート」と考えてください)。

ステートフルセッションBeanのステートフル部分は、サーブレットのセッションに似ています。ステートフルセッションBeanを使用すると、Webクライアントがなくても、アプリでそのセッションを維持できます。アプリサーバーがステートレスセッションBeanをオブジェクトプールからフェッチすると、特定のユーザーに関連付けられていないため、任意のリクエストを満たすために使用できることがわかります。

ステートフルセッションBeanは、最初にそれを取得したユーザーに配布する必要があります。これは、ショッピングカート情報はユーザーだけが知っている必要があるためです。アプリサーバーは、これが正しいことを確認します。あなたが買い物を始めて、私がやって来たときにアプリサーバーがあなたのステートフルセッションBeanを私にくれたとしたら、あなたのアプリがどれほど人気が​​あるか想像してみてください!

したがって、プライベートデータメンバーは確かに「状態」ですが、「ショッピングカート」ではありません。インクリメントされた変数が特定のユーザーに関連付けられるように、(非常に良い)例をやり直してみてください。それをインクリメントし、新しいユーザーを作成して、インクリメントされた値がまだ表示されるかどうかを確認します。正しく行われると、すべてのユーザーに自分のバージョンのカウンターだけが表示されます。

于 2010-02-28T13:57:09.053 に答える
18

このコンテキストでのステートレスおよびステートフルは、期待することをまったく意味しません。

EJBのステートフルネスとは、私が会話状態と呼んでいるものを指します。典型的な例は、フライトの予約です。3つのステップで構成されている場合:

  • 予約席
  • クレジットカードに請求する
  • チケット発行

それらのそれぞれがセッションBeanへのメソッド呼び出しであると想像してください。ステートフルセッションBeanは、この種の会話を維持できるため、呼び出しの間に何が起こったかを記憶します。

ステートレスセッションBeanには、会話状態のためのそのような容量がありません。

セッションBean(ステートレスまたはステートフル)内のグローバル変数は、まったく別のものです。ステートフルセッションBeanには作成されたBeanのプールがあります(Beanは一度に1つの会話でしか使用できないため)が、ステートレスセッションBeanにはインスタンスが1つしかないことが多く、グローバル変数が機能しますが、私は思いませんこれは必然的に保証されます。

于 2010-02-28T13:59:06.547 に答える
7

良い質問、

このコードを試してください(MyBeanステートフル/ステートレスを変更してください)。

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());
    }

}

ケース: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

ケース: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

于 2018-10-23T08:22:16.720 に答える
5

2つの主要なタイプのセッションBeanの主な違いは次のとおりです。

ステートレスビーンズ

  1. ステートレスセッションBeanは、メソッドを呼び出したクライアントとの会話状態がないものです。このため、複数のクライアントと対話するために使用できるオブジェクトのプールを作成でき ます。
  2. クライアントごとの状態がないため、パフォーマンス面ではステートレスBeanの方が優れています。
  3. 複数のクライアントからの複数のリクエストを並行して処理できます。

ステートフルビーンズ

  1. ステートフルセッションBeanは、一度に複数のクライアントとの会話状態を維持でき、タスクはクライアント間で共有されません。
  2. セッションが完了した後、状態保持されません。
  3. コンテナは、状態をシリアル化して、将来使用するために古い状態として保存できます。これは、アプリケーションサーバーのリソースを節約し、Beanの障害をサポートするために行われます。
于 2017-02-20T20:08:31.937 に答える
4

これは、コンテナのプールにBeanインスタンスが1つしかなく、すべての呼び出しで再利用されているために発生します。クライアントを並行して実行すると、コンテナーがプール内により多くのBeanインスタンスを作成するため、異なる結果が表示されます。

于 2013-05-28T22:25:29.883 に答える
4

良い答えがあります。ちょっとした答えを付け加えたいと思います。ステートレスBeanは、クライアントデータを保持するために使用しないでください。「ワンショットで実行できるアクションまたはプロセスをモデル化する」ために使用する必要があります。

于 2016-03-27T05:26:22.487 に答える