0
public class Test1(){  
  public vod method1(){  
    try{  
        Hashtable<String, String> env = new Hashtable<String, String>();  
        env.put(Context.INITIAL_CONTEXT_FACTORY, EJB_JNDI_FACTORY);  
        env.put(Context.PROVIDER_URL, EJB_URL);  
        InitialContext ctx = new InitialContext(env);             
        LogSearchRemote logSearchRemote = (LogSearchRemote) ctx.lookup(LOG_SEARCH_EJB_BINDNAME);  
        System.out.println("logSearchRemote = " + logSearchRemote);  
        logSearchRemote.setTest(5);  
        System.out.println("logSearchRemote.getTest() = " + logSearchRemote.getTest());  
        System.out.println("logSearchRemote.getTestAgain() = " + logSearchRemote.getTestAgain());  
        LogSearchRemote logSearchRemote2 = (LogSearchRemote) ctx.lookup(LOG_SEARCH_EJB_BINDNAME);  
        System.out.println("logSearchRemote2 = " + logSearchRemote2);  
        System.out.println("logSearchRemote2.getTest() = " + logSearchRemote2.getTest());  
        System.out.println("logSearchRemote2.getTestAgain() = " + logSearchRemote2.getTestAgain());  
        this.session = session;  
        session.setAttribute("LogSearchEJB", logSearchRemote);  
        System.out.println("logSearchRemote = " + logSearchRemote);  
    }catch(Exception e){  
        e.printStackTrace();  
    }  
  // if @stateless, throw exception "$Proxy53 cannot be cast to hk.gov.ehr.service.tch.als.admin.logsearch.ejb.LogSearchRemote"  
  // if @stateful, no error!!  
LogSearchRemote logSearchRemote = (LogSearchRemote)session.getAttribute("LogSearchEJB");  
  //.....  
  }  
}   

1) 上記のコードの場合、LogSearchRemote 実装 Bean がステートフルである場合、

   LogSearchRemote logSearchRemote = (LogSearchRemote)session.getAttribute("LogSearchEJB");

エラーはありませんが、LogSearchRemote 実装 Bean がステートレスの場合、例外「$Proxy53 は hk.gov.ehr.service.tch.als.admin.logsearch.ejb.LogSearchRemote にキャストできません」がスローされます。なぜですか?

2)ステートフル セッション Bean の場合、毎回

LogSearchRemote logSearchRemote = (LogSearchRemote) ctx.lookup(LOG_SEARCH_EJB_BINDNAME); 

異なるlogSearchRemote 実装 Bean を返します
が、ステートレスセッション Bean の場合は、毎回

LogSearchRemote logSearchRemote = (LogSearchRemote) ctx.lookup(LOG_SEARCH_EJB_BINDNAME);   

同じ豆を返す!!
なぜこの場合ですか?
ステートレス セッション Bean は状態を保持すべきではなく、各ルックアップは異なる実装 Bean を返す必要があると思います。

@Stateless(name = "AlsAdminLogSearch_1_0", mappedName = "ejb/AlsAdminLogSearch_1_0")  
public class LogSearchBean implements LogSearchRemote{  

    private int test;

    @Override  
    public void setTest(int value){  
        test = value;  
    }  

    @Override  
    public int getTest(){  
        return test;  
    }  

    @Override  
    public int getTestAgain(){  
        return test;  
    }  

//...methods  

}    

3) 電話したら

logSearchRemote.setTest(5);  
System.out.println("logSearchRemote.getTest() = " + logSearchRemote.getTest());  
System.out.println("logSearchRemote.getTestAgain() = " 
logSearchRemote.getTestAgain());   

ステートレス セッション Bean の場合、getTest() および getTestAgain() は、前のメソッド呼び出しでインスタンス変数「test」を記憶できます!!

なぜ覚えているのでしょうか?ステートレス セッション Bean は、メソッド呼び出しごとに異なる EJB インスタンスを呼び出すことは想定されていませんか?

4

1 に答える 1

1

ステートレス セッション Bean は「ステートレスな方法で」使用する必要がありますが、実際にはサーバーがインスタンスのプールを保持します (ベンダーの戦略によって異なります)。したがって、複数のルックアップでまったく同じインスタンスを受け取る可能性はありますが、決して保証されるものではありません。代わりに、異なるスレッドとクライアント インスタンスが同じステートレス EJB インスタンスを取得する可能性があるため、このステートレス EJB インスタンスを効果的に共有できます。次のクライアントがわからないため、ステートレス EJB は「ビジネス ロジックの状態」を内部的に保持すべきではありません。推奨されませんが、ステートレス EJB はもちろん、インスタンスの再利用時に外部の「ステートレス」リソースへの高速アクセスを可能にする内部技術状態を保持する場合があります。(Web や書籍で入手できる EJB ライフサイクル図を参照してください。)

一方、ステートフル セッション Bean は「ステートフルな方法で」使用する必要があります。つまり、しばらくの間状態を保持し、複数のクライアント要求にまたがることを目的としています。したがって、クライアントはルックアップ時に「新しいインスタンス」を受け取ることが保証されます。コンテナーは、最後の使用サイクルの終了後に実装が古い状態情報を「忘れる」かどうかを確認できないため、コンテナーはステートフル EJB をクライアントから切り離した後、単純に破棄します。ルックアップで新しいインスタンスを作成します。

これに関する問題は、(最後の) 参照を失った後、ステートフル EJB がスペースで失われ、コンテナーによってクリーンアップされるため、ステートフル EJB のクライアントは、計画された完全な使用サイクルの間、EJB への参照を保持および維持する必要があることです。一方、EJB ref はシリアライズ可能ではありません (私の知る限り) 。そのため、EJB ref を存続させるために、クライアントは EJB 使用サイクル中にシリアライズされないようにする必要があります。

さらに、しばらくして既存のステートフル EJB を見つけるための HttpSession 属性ルックアップに匹敵するルックアップ メカニズムについては知りません。ステートフル EJB は、実行中のクライアントに実際にバインドされているか、「存在しない」かのいずれかです。

その結果、ステートフル EJB を使用してユーザー セッション情報を何時間も保持するプロジェクトでは、ステートフル EJB ref を保持するために HttpSession 属性オブジェクトを使用することにしました。したがって、アプリケーションは HttpSession で「EJB ホルダー」オブジェクトをルックアップし、ステートフル EJB を再利用できます。しかし、Web コンテナーが HttpSession 属性オブジェクト (「EJB ホルダー」) をシリアライズすることを決定した場合、これは明らかに失敗します。これは、EJB ref がシリアライゼーションに耐えられないためです。HttpSession スコープでの「EJB ホルダー」の次のルックアップでは、Web コンテナーによってデシリアライズされますが、ステートフル EJB はその参照が切り離され、使用できなくなります。

于 2013-05-16T16:35:32.360 に答える