1. ホーム
  2. jsf

JSFで'binding'属性はどのように機能するのですか?いつ、どのように使うべきですか?

2023-08-05 01:29:23

質問

多くの資料がありますが 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 属性の値を返すために実行されます。 User ビーンに設定される。この値はHTML出力に出力される。

しかし、私はどのように binding がどのように機能するのか理解できませんでした。生成されたHTMLはどのようにして link プロパティの 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 はここに格納されていますか?

どのように解決するのですか?

それはどのように動作しますか?

JSFビュー(Facelets/JSPファイル)がビルド/リストアされるとき、JSFコンポーネントツリーが生成されます。このとき ビューのビルド時 で、すべての binding の属性が評価されます ( と共に id 属性と、JSTL のようなタグハンドラによって ). JSF コンポーネントをコンポーネントツリーに追加する前に作成する必要がある場合、JSF は、コンポーネントツリーに追加される前に binding 属性が事前に作成されたコンポーネントを返すかどうかを確認します(つまり、非 null ) を返し、もしそうなら、それを使います。もしそれが事前に作成されていないなら、JSFはコンポーネントを"通常の方法"で自動作成し、その後ろにあるセッターを呼び出します。 binding 属性の後ろのセッターを、自動生成されたコンポーネントインスタンスを引数として呼び出します。

効果としては、コンポーネントツリー内のコンポーネントインスタンスの参照をスコープ付き変数に束縛します。この情報は、コンポーネント自体の生成された HTML 表現では決して見えません。この情報は、いずれにせよ、生成される HTML 出力には全く関係ありません。フォームが送信され、ビューが復元されると、JSFコンポーネントツリーはゼロから再構築され、すべての binding 属性は上の段落で説明したように再評価されます。コンポーネントツリーが再作成された後、JSFはJSFビューの状態をコンポーネントツリーにリストアします。

コンポーネントインスタンスはリクエストスコープされています!

知っておくべき重要なことは、具象コンポーネントインスタンスが効果的にリクエストスコープされていることです。それらはすべてのリクエストで新しく作成され、それらのプロパティはリストア ビュー フェーズ中に JSF ビュー ステートから値で満たされます。したがって、コンポーネントをバッキングビーンのプロパティにバインドする場合、バッキングビーンは は絶対に リクエストスコープより広い範囲にあるべきです。また JSF 2.0仕様書 の3.1.5章を参照してください。

3.1.5 コンポーネントバインディング

...

コンポーネントバインディングは,しばしば,マネージド・ビーン作成機能によって動的にインスタンス化されるJavaBeansと組み合わせて使用される( Bean作成機能(5.8.1項 「VariableResolverとデフォルトのVariableResolver」参照)を介して動的にインスタンス化されるJavaBeanと組み合わせて使用されることがよくあります。 アプリケーション開発者は アプリケーション開発者は、コンポーネントバインディング式によって指されるマネージドBeanを "request "スコープに置くことを強く推奨します。 "request "スコープに置くことを強くお勧めします。 これは、セッションまたはアプリケーションスコープに配置すると、スレッドセーフが必要になるためです。 UIComponentインスタンスは、単一のスレッドの内部で実行することに依存するからです。また セッション」スコープにコンポーネントバインディングを配置する場合、メモリ管理にも悪影響を及ぼす可能性があります。

そうでなければ、コンポーネントインスタンスは複数のリクエストで共有され、おそらく " 重複したコンポーネントID ビューで宣言されたバリデータ、コンバータ、およびリスナーは、以前のリクエストから既存のコンポーネント インスタンスに再接続されるため、エラーと奇妙な動作が発生します。症状は明確で、コンポーネントがバインドされているのと同じスコープ内の各リクエストで、複数回、さらに1回実行されるのです。

また、高負荷時 (つまり、複数の異なる HTTP リクエスト (スレッド) がまったく同じコンポーネントインスタンスに同時にアクセスし、操作する場合) には、遅かれ早かれ、たとえば以下のようなアプリケーションクラッシュに直面するかもしれません。 UIComponent.popComponentFromEL でスレッドがスタックしています。 または JSF saveState() 中に HashMap の CPU 使用率が 100% でスレッドが停止する。 あるいは、いくつかの "strange" IndexOutOfBoundsException または ConcurrentModificationException は、JSF がビューの状態を保存したり復元したりするのに忙しく、JSF の実装ソースコードから直接やってくる (つまり、スタックトレースが示すように saveState() または restoreState() メソッドなど)を使用することができます。

また、一つのコンポーネントが基本的にコンポーネントツリー全体の残りの部分を参照するように getParent()getChildren() を使用すると、単一のコンポーネントをビューまたはセッションスコープドBeanにバインドするときに、本質的にHTTPセッションで全体のJSFコンポーネントツリーを無駄に保存していることになります。これは、ビューに比較的多くのコンポーネントがある場合、利用可能なサーバー メモリの点で、本当にコストがかかります。

使用方法 binding を使用することは悪い習慣です。

とはいえ binding をこのように使用し、コンポーネントインスタンス全体をBeanプロパティにバインドすることは、たとえリクエストスコープのBeanであっても、JSF 2.xではかなりまれな使用例であり、一般的にベストプラクティスではありません。これは、設計上の問題を示しています。通常、ビュー側でコンポーネントを宣言し、その実行時属性を value のような実行時属性、そしておそらく他の styleClass , disabled , rendered などを、通常のビーンプロパティに変換します。そして、コンポーネント全体を取得して属性に関連付けられたセッターメソッドを呼び出す代わりに、まさにそのビーンプロパティを操作するだけです。

静的なモデルに基づいてコンポーネントを動的に構築する必要がある場合、より良いのは ビュービルドタイムタグを使用するのが良いでしょう。 を使用することです。 タグファイル の代わりに createComponent() , new SomeComponent() , getChildren().add() といった具合です。また どのように古いJSPのスニペットをJSFの同等物にリファクタリングしますか?

あるいは、動的なモデルに基づいてコンポーネントを動的にレンダリングする必要がある場合、単に イテレータコンポーネント ( <ui:repeat> , <h:dataTable> など)。参照 JSFコンポーネントを動的に追加する方法 .

コンポジットコンポーネントは全く別の話です。コンポーネントを <cc:implementation> 内のコンポーネントをバッキングコンポーネント(つまり <cc:interface componentType> . a.o. も参照してください。 java.util.Dateをf:convertDateTimeを用いて時間と分を表す二つのh:inputTextフィールド上に分割します。 JSF 2.0コンポジットコンポーネントで動的リストを実装する方法は?

使用するのは binding ローカルスコープで

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

こちらもご覧ください。