それはどのように機能しますか?
JSF ビュー (Facelets/JSP ファイル) が構築/復元されると、JSF コンポーネント ツリーが生成されます。その時点で、ビューのビルド時間、すべてのbinding
属性が評価されます (属性および JSTL などのタグハンドラーとともにid
)。コンポーネント ツリーに追加する前に JSF コンポーネントを作成する必要がある場合、JSF はbinding
属性が事前に作成されたコンポーネント (つまり、非) を返すかどうかを確認null
し、そうであればそれを使用します。事前に作成されていない場合、JSF は「通常の方法」でコンポーネントをbinding
自動作成し、自動作成されたコンポーネント インスタンスを引数としてセッターの背後にある属性を呼び出します。
実際には、コンポーネント ツリー内のコンポーネント インスタンスの参照をスコープ付き変数にバインドします。この情報は、コンポーネント自体の生成された HTML 表現には決して表示されません。とにかく、この情報は、生成された HTML 出力には関係ありません。フォームが送信され、ビューが復元されると、JSF コンポーネント ツリーがゼロから再構築され、すべてのbinding
属性が上記の段落で説明したように再評価されます。コンポーネント ツリーが再作成された後、JSF は JSF ビュー ステートをコンポーネント ツリーに復元します。
コンポーネント インスタンスはリクエスト スコープです。
知って理解することが重要なのは、具体的なコンポーネント インスタンスが事実上リクエスト スコープであることです。これらはリクエストごとに新しく作成され、ビューの復元段階でプロパティに JSF ビュー状態の値が入力されます。そのため、コンポーネントをバッキング Bean のプロパティにバインドする場合、バッキング Bean は絶対にリクエスト スコープよりも広いスコープにあってはなりません。JSF 2.0仕様の章3.1.5も参照してください。
3.1.5 コンポーネントバインディング
...
コンポーネント バインディングは、マネージド Bean 作成機能を介して動的にインスタンス化される JavaBeans と組み合わせて使用されることがよくあります (セクション 5.8.1「VariableResolver とデフォルトの VariableResolver」を参照してください)。アプリケーション開発者は、コンポーネント バインディング式が指すマネージド Bean を「リクエスト」スコープに配置することを強くお勧めします。これは、UIComponent インスタンスが単一のスレッド内での実行に依存するため、セッションまたはアプリケーション スコープに配置するとスレッド セーフが必要になるためです。コンポーネント バインディングを「セッション」スコープに配置すると、メモリ管理に悪影響が及ぶ可能性もあります。
そうしないと、コンポーネント インスタンスが複数のリクエスト間で共有され、ビューで宣言されたバリデータ、コンバータ、およびリスナが以前のリクエストから既存のコンポーネント インスタンスに再アタッチされるため、「コンポーネント ID の重複」エラーと「奇妙な」動作が発生する可能性があります。症状は明らかです。コンポーネントがバインドされているのと同じスコープ内の各リクエストで、複数回実行されます。
また、負荷が高い場合 (つまり、複数の異なる HTTP 要求 (スレッド) がまったく同じコンポーネント インスタンスに同時にアクセスして操作する場合)、遅かれ早かれ、UIComponent.popComponentFromELでスレッドがスタックしたり、スレッドがスタックしたりするなどのアプリケーション クラッシュに直面する可能性があります。 JSF saveState() 中の HashMap での 100% の CPU 使用率IndexOutOfBoundsException
、またはConcurrentModificationException
JSF がビュー ステートの保存または復元でビジー状態である間に、JSF 実装ソース コードから直接発生する「奇妙な」ものでさえあります (つまり、スタック トレースはsaveState()
、またはrestoreState()
メソッドなどを示します)。
また、単一のコンポーネントは基本的にgetParent()
およびを介してコンポーネント ツリー全体の残りを参照するgetChildren()
ため、単一のコンポーネントをビューまたはセッション スコープの Bean にバインドすると、基本的に JSF コンポーネント ツリー全体が HTTP セッションに保存されます。ビューに比較的多くのコンポーネントがある場合、これは使用可能なサーバー メモリの点で非常にコストがかかります。
Bean プロパティでの使用binding
は悪い習慣です
とにかく、binding
この方法を使用して、リクエスト スコープの Bean であっても、コンポーネント インスタンス全体を Bean プロパティにバインドすることは、JSF 2.x ではかなりまれなユース ケースであり、通常はベスト プラクティスではありません。デザイン臭を示します。通常は、ビュー側でコンポーネントを宣言し、 や、、value
などのランタイム属性を通常の Bean プロパティにバインドします。次に、コンポーネント全体を取得して属性に関連付けられたセッター メソッドを呼び出す代わりに、目的の Bean プロパティを正確に操作するだけです。styleClass
disabled
rendered
静的モデルに基づいてコンポーネントを「動的にビルド」する必要がある場合は、必要に応じてタグ ファイルで、などの代わりにJSTLなどのビュー ビルド時間タグを使用することをお勧めします。古い JSP のスニペットを JSF に相当するものにリファクタリングする方法も参照してください。createComponent()
new SomeComponent()
getChildren().add()
または、動的モデルに基づいてコンポーネントを「動的にレンダリング」する必要がある場合は、イテレータ コンポーネント( <ui:repeat>
、<h:dataTable>
など) を使用します。JSF コンポーネントを動的に追加する方法も参照してください。
複合コンポーネントは、まったく別の話です。<cc:implementation>
a 内のコンポーネントをバッキング コンポーネント (つまり、 で識別されるコンポーネント)にバインドすることは完全に正当<cc:interface componentType>
です。 ao も参照してください。 ao f:convertDateTime を使用して時間と分を表す 2 つの h:inputText フィールドに java.util.Date を分割するおよびHow to implement a dynamic list with with JSF 2.0 複合コンポーネント?
binding
ローカルスコープでのみ使用
ただし、アクション/値に依存する検証に関連するユースケースでは、特定のコンポーネント内から別のコンポーネントの状態について知りたい場合があります。そのために、binding
属性を使用できますが、Bean プロパティと組み合わせて使用することはできません。そのようにローカルELスコープで一意の変数名をbinding
属性に指定するだけbinding="#{foo}"
で、コンポーネントは同じビューの別の場所で応答をレンダリング中にUIComponent
、#{foo}
. そのような解決策が回答で使用されているいくつかの関連する質問を次に示します。
以下も参照してください。