web-dev-qa-db-ja.com

JSFリクエストスコープBeanは、リクエストごとに新しいステートフルセッションBeanを再作成し続けますか?

私は最初のJava EEアプリケーションをJSF、PrimeFaces、Glassfish、Netbeansを使用して構築しています。私は新しいので、コアの問題に間違ってアプローチしている可能性があります。

主要な問題:ユーザーの情報を安全に維持したい。 JSFセッションBeanで維持するか、ステートフルセッションEJBで維持するかについては、矛盾する考えがあるようです。ステートフルセッションEJBを使用しようとしています。その方が、より安全だからです。

問題は、アプリケーションがそのBeanを作成して再利用することを期待しているときに、そのBeanの複数のインスタンスを作成しているように見えることです。ページを更新すると、@PostConstruct@PostActivateが3回実行され、それらはすべて異なるインスタンスで実行されます。その後、アプリケーションを再デプロイすると、それらはすべて破棄されます。

それがどのように機能するかを誤解しましたか、または何かが間違って構成されていますか?

切り捨てられたコードサンプルを表示してみます。

basic.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://Java.Sun.com/jsf/html"
      xmlns:c="http://Java.Sun.com/jsp/jstl/core">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
        Hello from Facelets
        <c:if test="#{loginController.authenticated}">
            Authenticated
        </c:if>
        <c:if test="#{loginController.authenticated}">
            Authenticated
        </c:if>
        <c:if test="#{loginController.authenticated}">
            Authenticated
        </c:if>
    </h:body>
</html>

LoginController

@Named(value = "loginController")
@RequestScoped
public class LoginController implements Serializable {

    @EJB
    private UserBeanLocal userBean;

    public boolean isAuthenticated() {
        return userBean.isAuthenticated();
    }

}

UserBeanUserBeanLocalインターフェースを除く)

@Stateful
public class UserBean implements UserBeanLocal, Serializable {

    boolean authenticated = false;

    @PostConstruct
    @PostActivate
    public void setup(){
        System.out.println("##### Create user Bean: "+this.toString());
    }

    @Override
    public boolean isAuthenticated() {
        System.out.println("########## Authentication test is automatically passing.");
        authenticated = true;//hard coded for simplicity.
        return authenticated;
    }     

    @PrePassivate
    @PreDestroy
    public void cleanup(){
        System.out.println("##### Destroy user Bean");
    }

}

最後に、3回更新した後のGlassfishの出力は次のとおりです。

INFO: ##### Create user Bean: boundary._UserBean_Serializable@2e644784
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ##### Create user Bean: boundary._UserBean_Serializable@691ae9e7
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ##### Create user Bean: boundary._UserBean_Serializable@391115ac
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
32
Alan B. Dee

ステートフルセッションBean(SFSB)は、あなたが思っているものとは異なります。セッションスコープのJSFマネージドBeanのように動作すると思われるかもしれません。これは真実ではありません。 EJBの「セッション」という用語は、あなたが考えていたHTTPセッションとはまったく異なる意味を持っています。

EJBの「セッション」は、トランザクションコンテキストで解釈する必要があります。 SFSBの場合、クライアントが存続している限り、トランザクション(基本的にはDBセッション)は存続します。 SFSBのクライアントは、特定の例ではなくWebブラウザーですが、JSFマネージドBeanインスタンス自体、まさにSFSBが注入されたインスタンスです。 JSFマネージドBeanをリクエストスコープに配置したため、SFSBは、JSFマネージドBeanとともにすべてのHTTPリクエストで再作成されます。

例として、JSFマネージドBeanをビュースコープに配置してみてください。ビュースコープは、たとえば、同じページのマルチステップフォームに役立ちます。ビューがそれ自体にポストバックするたびに、同じJSFマネージドBeanインスタンスが再利用され、このインスタンスにより、SFSBの同じインスタンスにアクセスできます。 Beanが作成されたときであり、他の場所で共有されていません。 SFSBトランザクションは、クライアント(ビュースコープのJSFマネージドBean)が存続する限り存続します。

ステートレスセッションBean(SLSB)は他の場所で共有できますが、とにかくステートレスとして扱われることを目的としているため、これは問題ではありません。この「機能」は、コンテナを作成および保存するための時間とメモリを節約します。コンテナはそれらのプールを持つことができます。さらに、ビュー、セッション、またはアプリケーションスコープのJSFマネージドBeanに挿入されるSLSBインスタンスは、JSFマネージドBeanの作成時とまったく同じインスタンスをすべてのHTTPリクエストで参照する必要はありません。コンテナのプールで使用可能なインスタンスによっては、完全に異なるインスタンスになることもあります。トランザクションは、SLSBで単一のメソッドが呼び出される限り(デフォルトで)存続します。

とはいえ、SFSBは、「ログインしたユーザーを記憶する」という特定のケースには適していません。それが「より安全」であるということは、実際には意味がありません。 JSFマネージドBeanをセッションスコープに配置し、ログインしたユーザーをそれ自体で記憶させ、SLSBを使用してビジネスアクション(DBとの対話など)を実行し、必要な場合にのみSFSBを使用しますrealステートフルセッションBean(nowはそれらが正確に何であるかを理解していると思います:))。

参照:

59
BalusC

私の調査と使用法から理解できる限り、EJB SFSBはJSFであるため、Webアプリケーションには役立ちません。Springはユーザーごとのセッションを維持するためにhelfullアノテーションを提供します。ただし、WebサービスとRPCメソッドの呼び出し呼び出しが必要なアプリケーションが実行されている場合、EJB SFSBは、ユーザーごとのセッション(トランザクション)を維持するために必要です。

2
Ahmet Karakaya