7

ここで、JSF2.xのrequestScopedBeanでセッションを作成することに疑問があります。sessionScoped Beanを直接使用してユーザーに必要なデータを配置できるため、JSF2.xでセッションを作成する必要がないことを理解しています。しかし、私は最近、開発者がセッションのインスタンス変数を作成し、以下のようにfacescontextからセッションを取得するJSFコードを紹介されました

 @ManagedBean
 @RequestScoped
 Public class someClass(){

 FacesContext facesContext = FacesContext.getCurrentInstance();
 HttpSession session = (HttpSession) facesContext.getExternalContext().getSession(true);

 public void someFunction(){

 //Some code here..

 session.setAttribute("key","value");

 //Some code here..

 }

  //rest of the code here...
 }

さて、インスタンス変数として「session」を使用するべきではなく、JSF 2で明示的にセッションを取得する必要はなく、sessionScopedBeanを使用する必要があることを伝えました。

最初に「インスタンス変数としてセッションを維持することはスレッドセーフではない」という理由を示し、2番目のステートメントには「すでに提供されているJSFセッションの回避策を実行している」と述べました。

私が得た反論は、最初の理由は「私たちがWebアプリケーションであるため、マルチスレッドの問題はない」というものでした。2番目に、「とにかく、リクエストが処理されるとセッション変数がクリアされるので、ここで問題はありませ

私にはそれを修正する他の長所はありませんでしたので、私の質問は、1)それらは正しいですか?2)私たちがすべき方法でやるべきである他の特定の理由はありますか?3)そして最後に、彼らにそのように使用するように促したかもしれない何か?

誰か詳しく説明してもらえますか?訂正してください。ありがとう

4

3 に答える 3

7

HttpSessionJava EE 6で定義されているように、インターフェースは、ユーザーアクションのグループ化、ユーザーによって実行された継続的なアクションの識別、および複数のページ要求にわたるそのユーザーに関する情報の保存の方法を提供します。

総括

セッションは明らかに多くのリクエスト間で共有されるため、スレッドセーフの問題とその影響が生じます。サーブレット3.0仕様のセッションに関する第7章では、このような問題に対処することの重要性がサポートされている場合があります。

リクエストスレッドを実行する複数のサーブレットは、同じセッションオブジェクトに同時にアクティブにアクセスできる場合があります。コンテナは、セッション属性を表す内部データ構造の操作がスレッドセーフな方法で実行されることを保証する必要があります。開発者は、属性オブジェクト自体にスレッドセーフにアクセスする責任があります。これにより、HttpSessionオブジェクト内の属性コレクションが同時アクセスから保護され、アプリケーションがそのコレクションを破損させる可能性がなくなります。

サーブレット3.0仕様(JSR-315)、ch。7.7.1、私の強調。

しかし、このすべての混乱はどこから生じているのでしょうか?AJAX以前のWebアプリケーションの時代には、同じユーザーがセッションにアクセスする可能性はほとんどなかったため、開発者は同期についてあまり気にしませんでした。しかし、AJAX対応のWebアプリケーションを構築する傾向が高まっているため、同じユーザーからの2つの要求が同時に発生し、セッションに同時にアクセスする可能性が非常に高くなります。

ちなみに、サーブレットのインターフェースを使用することで、スレッドの問題をわずかに減らすことができますSingleThreadModelが、その適用の必要性については議論があります(サーブレット3.0仕様(JSR-315)、ch。2.2.1)。さらに、サーブレット3.0および「HttpSessionのインスタンスなど、一度に複数のサーブレットインスタンスにアクセスできるオブジェクトは、SingleThreadModelを実装するサーブレットを含む複数のサーブレットでいつでも利用できる可能性がある」ため、非推奨になりました。

同期に関する問題

Java EE 6チュートリアルでは、「複数のWebコンポーネントがセッションに格納されているオブジェクトにアクセスすると、同時アクセスが発生する可能性がある」と明示的に述べられています(Java EE 6チュートリアル、第II-15章)。HttpSessionさらに、インターフェースを詳しく見ると、オブジェクトをセッションにバインドできるいくつかのメソッドが見つかります。これにより、複数のユーザー接続間でユーザー情報を保存できるため、HTTPプロトコルのステートレス性が克服されます。これらのメソッドは次のとおりです。

  • getAttribute(String name)(および現在非推奨になっているgetValue(String name));
  • setAttribute(String name, Object value)(そして現在非推奨になっているputValue(String name, Object value);
  • removeAttribute(String name)(および現在非推奨になっているremoveValue(String name));
  • invalidate()
  • インターフェイスの他のメソッド。

最後のメソッドは、このセッションを無効にし、ユーザー情報を保持しているオブジェクトをバインド解除します。したがって、これは私たちが恐れていることではありません。最も重要なメソッドは、Objectセッションから/セッションへのsの読み取り、書き込み、および削除を行うメソッドです。これらのメソッドは、異なるスレッドによって同時にデータを処理/アクセスするために呼び出されるためです。

Brian GoetzがJavaの理論と実践で述べているように、同時アクセスの明らかな問題は次のとおりです。すべてのステートフルWebアプリケーションが壊れていますか?

  • アトミック障害。1つのスレッドが複数のデータを更新し、別のスレッドが一貫性​​のない状態にあるときにデータを読み取り、
  • 読み取りスレッドと書き込みスレッドの間の可視性の失敗。一方のスレッドはデータを変更しますが、もう一方のスレッドは古いデータまたは一貫性のない状態のデータを確認します。

問題の簡単な解決策

彼は後に、Webアプリケーション内の並行性の問題を減らす5つの手法を提案し、最後に「HttpSessionで要求をシリアル化すると、多くの並行性の危険がなくなる」と述べています。Marty Hallは、セッショントラッキングに関するオンラインチュートリアルで、同期について次のように提案しています。「同期されたブロックのラベルとして、セッションまたはおそらくセッションの値を使用してください」。したがって、基本的な設定は次のとおりです。

HttpSession session = request.getSession();
synchronized(session) {
    SomeClass value = (SomeClass)session.getAttribute("someID");
    if (value == null) {
        value = new SomeClass(...);
    }
    doSomethingWith(value);
    session.setAttribute("someID", value);
}

この設定では、セッションにアクセスするための重複するリクエストが同期されます。

スレッドセーフでない使用法の例

HttpSession session = request.getSession();
MyClass myClass = (MyClass)session.getAttribute("myClass");
if(myClass != null) {
    myClass.performOperation();
    session.setAttribute("myClass", myClass);
}

JSFでのセッションによる明示的な操作の必要性

セッションオブジェクト内のデータの操作が同時実行の問題につながる可能性があることは明確に理解されています。さらに、セッションオブジェクトを暗黙的に管理するJSFフレームワーク内で開発することを選択した場合、その適用性は疑わしいものになります。

結局、オブジェクトが本質的にそこに属している場合は、オブジェクトをセッションに入れることになっています。開発者は、問題を解決する手段としてオブジェクトをセッションに配置する傾向がありますが、通常はより良い方法があります。いくつかの間違いは、記事JSFベストプラクティス: ThomasAselによるクリーンセッションのスコープ管理でカバーされています。

スレッドの問題を軽減するいくつかの方法

スレッドの問題のほとんどは、HttpSessionが間違った方法で使用された場合に発生します。この観点から、スレッディングの問題はスコーピングの問題の結果です。

たとえば、より狭いスコープ、つまりリクエストスコープまたはビュースコープに属すると想定されるセッションに値を設定すると、コードは有形の確率でcuncurrencyの問題に対して脆弱になります。代わりに、すべてのセッションデータが適切なスコープに属している場合、ユーザーが同時実行の問題に直面する可能性は非常に低くなります。

@SessionScopedJSFが最終的にそれらのBeanを、管理対象Beanの名前をキーとしての属性として格納するとすぐに、 Beanスレッドの安全性を開発者が確保する必要があります。HttpSession名前によるマネージドBeanへのアクセスは、JSFでは便利であり、私が知る限り、によって行われるカバーの下にありますsession.getAttribute("managedBeanName")

このコンテキストでは、ユーザーがセッションに正しいデータを配置し、それを正しく管理した場合(つまり、セッションを妨害せずに解決する必要のある問題を解決しなかった場合)、私が見る唯一の欠点はBalusCの回答に記載されています。 「密結合と悪い設計」。それ以外の場合(JSFがカバーの下でBeanのライフサイクルを正しく管理し、設計上の問題が発生することを省略した場合)、使用法は類似しています。

頭に浮かぶ並行性の問題を引き起こすスコープの問題のいくつかの例:

  • セッション中のユーザー情報(ユーザー認証の詳細、ユーザー設定、国際化されたWebアプリケーションでのロケールの選択)に関連するもの以外のものの保存。
  • ビュー間での情報の共有は、セッションを使用して行うべきではありません。データの取得はリクエストによって行うGET必要があり、データの操作はリクエストによって行う必要がありPOSTます。ページ転送中にデータを渡すことは、たとえば、を使用して<f:setPropertyActionListener>行うことができ、ページリダイレクト中にデータを渡すことは、たとえば、#{flash}属性を使用して行うことができる。
  • 繰り返されるコンポーネントのセットアップで情報を渡すことは、セッションを妨害することなく、、、、および情報の取得を介し<f:attribute>て、<f:setPropertyActionListener>アクション<f:param>(リスナー)メソッド<f:viewParam>などを介して実行する必要があります。

要約すると、上記のリストに厳密に従わないと、もちろんいつか誤った出力が表示されますが、セッションスコープに属する適切なデータを選択した場合、問題はほとんど発生しません。通常、このデータの選択は、ユーザーセッションの質問全体で必要な情報に答えるときに行うことができます。

そうは言っても、よくある間違いは、情報をセッションに入れて後続のビューで利用できるようにし、その情報を取得してからセッションから削除することです。これは明らかに間違っています。私は、このアプローチがあなたの対話者によって採用されたと強く信じています。

結局、JSFは開発タスクを容易にするために進化しているので、その便利な機能を使用してみませんか?

于 2013-03-12T18:27:05.640 に答える
4

これは理論的には機能しますが、これは単に密結合であり、設計が不適切です。@RequestScopedからへの非常に小さな変更@ViewScopedは、Webアプリケーション全体を完全に強制終了します。これは間違いなく正しくありません。バッキングBeanクラスは、宣言されているスコープに技術的に影響されないように設計する必要があります。

FacesContextまたはそのアーティファクトをバッキングBeanのプロパティとして割り当てないでください。ただし、言い訳はせずに、常にスレッドローカルスコープでアクセスしてください。

于 2013-03-13T20:21:43.227 に答える
3

コードを取得した後、コードで何が起こっているのかわかりませんsession。実際、すべてがコードに依存しています。

マルチスレッドの問題では、セッションから何かを読んでいるだけなら問題はないと言わざるを得ません。セッションに書き込むとき、大きな問題が発生する可能性があります。1つのセッションで複数のリクエスト(AJAXリクエスト、複数のタブなど)が実行されると、競合状態が発生するため、セッションに実際に何が書き込まれているかを確認できません。

JSFセッションとHTTPセッションはなく、セッションは1つだけで、それがHTTPセッションです。JSFはそのセッションにファサードを提供するだけなので、その時点から、セッションの取得方法に問題はありません。一部の属性をセッションに追加しても問題ない場合もありますが、制御する必要があり、制限する必要があります。たとえば、このバッキングBeanでいくつかのデータを生成でき、そのデータは別のウィンドウに表示される必要があります(たとえば、いくつかのレポート)。レポートデータをセッションに追加できます。別のページでそれらのデータを取得したら、セッションから削除します。これらのページは1つのフローに含まれ、それらの間に何もないため、これは制限されます。しかし、そのメソッドが別の目的で呼び出された場合も、それは問題です。

于 2013-03-11T21:30:13.113 に答える