web-dev-qa-db-ja.com

JSFで「バインディング」属性はどのように機能しますか?いつ、どのように使用すべきですか?

JSFでは、value属性とbinding属性を区別する多くの資料があります。

両方のアプローチが互いにどのように異なるかに興味があります。与えられた:

public class User {
    private String name;
    private UICommand link;

    // Getters and setters omitted.
}
<h:form>
    <h:commandLink binding="#{user.link}" value="#{user.name}" />
</h:form>

value属性が指定されたときに何が起こるかは非常に簡単です。ゲッターが実行され、name BeanのUserプロパティ値が返されます。値はHTML出力に出力されます。

しかし、bindingがどのように機能するのか理解できませんでした。生成されたHTMLは、link BeanのUserプロパティとのバインディングをどのように維持しますか?

以下は、手作業による美化とコメント化後に生成された出力の関連部分です(id j_id_jsp_1847466274_1は自動生成され、2つの非表示入力ウィジェットがあることに注意してください)。 SunのJSF RIバージョン1.2を使用しています。

<form action="/TestJSF/main.jsf" enctype="application/x-www-form-urlencoded"
    id="j_id_jsp_1847466274_1" method="post"  name="j_id_jsp_1847466274_1">
    <input name="j_id_jsp_1847466274_1" type="hidden" value="j_id_jsp_1847466274_1">
    <a href="#" onclick="...">Name</a>
    <input autocomplete="off" id="javax.faces.ViewState" name="javax.faces.ViewState"
        type="hidden" value="-908991273579182886:-7278326187282654551">
</form>

bindingはどこに保存されていますか?

71
John

どのように機能しますか?

JSFビュー(Facelets/JSPファイル)が構築/復元されると、JSFコンポーネントツリーが作成されます。その瞬間、 ビュー構築時間 、すべてのbinding属性が評価されます( id属性とJSTLのようなタグハンドラー )。コンポーネントツリーに追加する前にJSFコンポーネントを作成する必要がある場合、JSFはbinding属性が事前に作成されたコンポーネント(つまり、_null以外)を返すかどうかを確認し、返す場合はそれを使用します。事前に作成されていない場合、JSFはコンポーネントを「通常の方法」で自動作成し、自動作成されたコンポーネントインスタンスを引数としてbinding属性の背後にあるセッターを呼び出します。

効果では、コンポーネントツリーのコンポーネントインスタンスの参照をスコープ変数にバインドします。この情報は、コンポーネント自体の生成されたHTML表現には決して表示されません。とにかく、この情報は、生成されたHTML出力に関連するものではありません。フォームが送信され、ビューが復元されると、JSFコンポーネントツリーが最初から再構築され、すべてのbinding属性が上の段落で説明したように再評価されます。コンポーネントツリーが再作成された後、JSFはJSFビューステートをコンポーネントツリーに復元します。

コンポーネントインスタンスはリクエストスコープです!

知っておくべき重要なことは、具象コンポーネントのインスタンスが効果的にリクエストスコープされていることです。これらはすべてのリクエストで新しく作成され、それらのプロパティには、ビューの復元段階でJSFビューステートからの値が入力されます。そのため、コンポーネントをバッキングBeanのプロパティにバインドする場合、バッキングBeanはabsolutely notリクエストスコープよりも広いスコープ内にある必要があります。 JSF 2.0仕様 3.1.5章も参照してください。

3.1.5コンポーネントのバインド

...

コンポーネントバインディングは、マネージドBean作成機能を介して動的にインスタンス化されるJavaBeansと組み合わせて使用​​されることがよくあります(セクション5.8.1「VariableResolverとデフォルトVariableResolver」を参照)。 アプリケーション開発者は、コンポーネントバインド式が指すマネージドBeanを「要求」スコープに配置することを強くお勧めします。これは、UIComponentインスタンスがセッションまたはアプリケーションスコープに配置されると、スレッドセーフが必要になるためですシングルスレッド内で実行することに依存します。また、コンポーネントバインディングを「セッション」スコープに配置すると、メモリ管理に悪影響を与える可能性があります。

そうでない場合、コンポーネントインスタンスは複数のリクエスト間で共有され、ビューで宣言されたバリデーター、コンバーター、リスナーが既存のコンポーネントインスタンスに再アタッチされるため、「 duplicate component ID 」エラーと「奇妙な」動作が発生する可能性があります前のリクエストから。症状は明らかです。複数回実行され、コンポーネントがバインドされているのと同じスコープ内の各リクエストでさらに1回実行されます。

また、負荷が高い場合(つまり、複数の異なるHTTPリクエスト(スレッド)が同じコンポーネントインスタンスに同時にアクセスして操作する場合)、遅かれ早かれ、たとえば IComponent.popComponentFromELでスタックスレッド 、または richfaces UIDataAdaptorBaseとその内部HashMapを使用したCPU使用率100%のJavaスレッド 、または「奇妙な」IndexOutOfBoundsExceptionまたはConcurrentModificationException JSFがビューステートの保存または復元に忙しい間、JSF実装ソースコードから直接来ます(つまり、スタックトレースはsaveState()またはrestoreState()メソッドなどを示します)。

Beanプロパティでbindingを使用するのは悪い習慣です

とにかく、この方法でbindingを使用すると、要求スコープBeanでさえ、コンポーネントインスタンス全体をBeanプロパティにバインドすることは、JSF 2.xではかなりまれなユースケースであり、一般的にベストプラクティスではありません。デザインの匂いを示しています。通常、ビュー側でコンポーネントを宣言し、valueなどのランタイム属性、およびおそらくstyleClassdisabledrenderedなどのその他のランタイム属性を通常のBeanプロパティにバインドします。次に、コンポーネント全体を取得して属性に関連付けられたセッターメソッドを呼び出す代わりに、必要なBeanプロパティを正確に操作します。

コンポーネントを静的モデルに基づいて「動的に構築」する必要がある場合、 JSTLなどの構築時タグを表示 を使用することをお勧めします。必要に応じて タグファイルcreateComponent()new SomeComponent()getChildren().add()の代わりに。 古いJSPのスニペットをJSFの同等のものにリファクタリングする方法 も参照してください。

または、動的モデルに基づいてコンポーネントを「動的にレンダリング」する必要がある場合は、単に イテレータコンポーネント<ui:repeat><h:dataTable>など)を使用します。 JSFコンポーネントを動的に追加する方法 も参照してください。

複合コンポーネントはまったく別の話です。 <cc:implementation>内のコンポーネントをバッキングコンポーネント(<cc:interface componentType>で識別されるコンポーネント)にバインドすることは完全に合法です。ao 時間を表す2つのh:inputTextフィールドにまたがるJava.util.Dateの分割f:convertDateTimeで分 および JSF 2.0複合コンポーネントで動的リストを実装する方法?

ローカルスコープでのみbindingを使用します

ただし、アクション/値に依存する検証に関連するユースケースでは、特定のコンポーネントの内部とは異なるコンポーネントの状態について頻繁に知りたい場合があります。そのためには、binding属性を使用できますが、Beanプロパティと組み合わせてnotを使用できます。 binding="#{foo}"のようにbinding属性でローカルELスコープの一意の変数名を指定するだけで、コンポーネントはUIComponent参照として同じビューの他の場所でレンダリング応答中に直接使用できます。 #{foo}。そのようなソリューションが答えに使用されているいくつかの関連する質問があります:

こちらもご覧ください:

121
BalusC

各JSFコンポーネントはそれ自体をHTMLにレンダリングし、生成するHTMLを完全に制御します。 JSFで使用できるトリックは多数あり、どのトリックを使用するかは、使用しているJSF実装によって異なります。

  • すべてのfrom入力に完全に一意の名前が付けられていることを確認します。これにより、フォームがレンダリングされたコンポーネントツリーにフォームが送信されたときに、各コンポーネントが値フォームを読み取れる場所を簡単に確認できます。
  • JSFコンポーネントは、サーバーに送信するjavascriptを生成できます。生成されたjavascriptは、コンポーネントによって生成されたため、各コンポーネントもバインドされている場所を認識しています。
  • Hlinkのようなものについては、クエリパラメータとして、またはURL自体の一部として、またはmatrxパラメータとして、URLにバインド情報を含めることができます。たとえば。

    http:..../somelink?componentId=123は、jsfがコンポーネントツリーを見て、リンク123がクリックされたことを確認できるようにします。またはhtp:..../jsf;LinkId=123

この質問に答える最も簡単な方法は、リンクが1つだけのJSFページを作成し、それが生成するHTML出力を調べることです。そうすれば、使用しているJSFのバージョンを使用して、これがどのように起こるかを正確に知ることができます。

1
ams