3

私は、最初の JAX-RS 2 実装の 1 つである RestEasy 3.0.2 を使用しており、Tomcat 7 内でアプリケーションを実行しています。また、CDI アダプターを介して RestEasy と統合されている WELD を介して、アプリケーションでインジェクションを利用しています。これまでのところ、すべて正常に動作しています。

ここで、ContainerRequestFilter の実装を作成して、受信リクエストがリソースに到達する前に認証を実行できるようにしました。JAX-RS 標準では、@Provider アノテーションが付けられたすべてのリソースおよびその他すべての JAX-RS コンポーネントに対してインジェクションが可能であると規定されています。

これは私のフィルター実装の簡略化されたバージョンです:

@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {

    @Inject
    AuthenticationProvider authenticationProvider;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        authenticationProvider.authenticate(requestContext);
    }
}

注: AuthenticationProvider@RequestScopedです。

一般に、このソリューションは機能します。コンポーネントが挿入され、要求が期待どおりに処理されています。

しかし、フィルターがどの範囲にあるのかはまだ疑問です。アプリケーション スコープの場合、決定論的テストでは検出できない「おかしな」同時実行性の問題が明らかに発生します。

さまざまなドキュメント、ガイド、および例を調べましたが、フィルターを使用した注入を使用したり、フィルターのスコープについて何かを述べたりするものは見つかりませんでした。

4

3 に答える 3

6

RestEasy の場合、答えはCDI 統合に関する RestEasy のドキュメントに記載されています。

スコープを明示的に定義しない CDI Bean は、デフォルトで @Dependent スコープです。この疑似スコープは、Bean が注入先の Bean のライフサイクルに適応することを意味します。通常のスコープ (リクエスト、セッション、アプリケーション) は、コンポーネントのライフサイクル境界を明示的に指定するため、JAX-RS コンポーネントにより適しています。したがって、resteasy-cdi モジュールはデフォルトのスコープを次のように変更します。

JAX-RS ルート リソースがスコープを明示的に定義しない場合、Request スコープにバインドされます。

JAX-RS プロバイダーまたは javax.ws.rs.Application サブクラスがスコープを明示的に定義しない場合、それは Application スコープにバインドされます。

そのため、@Provider アノテーションが付けられた JAX-RS フィルターは @ApplicationScoped です。

ドキュメントには、適切な注釈を付けることで、JAX-RS プロバイダーを任意のスコープに関連付けることができるとも書かれています。したがって、一般に、JAX-RS フィルターのスコープはカスタマイズできます。

@RequestScoped オブジェクトを @ApplicationScoped フィルターに挿入しても安全であることに注意することが重要です。これは、CDI が実際のオブジェクトではなくプロキシへの参照を挿入するためです。プロキシでメソッドが呼び出されると、バックグラウンドでリクエストごとにオブジェクトの個別のインスタンスが使用されます。

ここに対応するWELDドキュメント

4.9。クライアント プロキシ

Bean が依存オブジェクト (スコープ @Dependent) でない限り、注入された Bean のクライアントは通常、Bean インスタンスへの直接参照を保持しません。

アプリケーション スコープにバインドされた Bean が、リクエスト スコープにバインドされた Bean への直接参照を保持しているとします。アプリケーション スコープの Bean は、多くの異なる要求間で共有されます。ただし、各リクエストは、リクエスト スコープ Bean の異なるインスタンス、つまり現在のものを参照する必要があります。

...

したがって、Bean がデフォルトのスコープ @Dependent を持っていない限り、コンテナーはプロキシ オブジェクトを介して、注入されたすべての参照を Bean に間接的に転送する必要があります。このクライアント プロキシは、メソッド呼び出しを受け取る Bean インスタンスが現在のコンテキストに関連付けられているインスタンスであることを確認する役割を果たします。クライアント プロキシでは、セッション コンテキストなどのコンテキストにバインドされた Bean を、他の注入された Bean を再帰的にシリアライズすることなく、ディスクにシリアライズすることもできます。

これを検証するために次のコードを使用しました (この例では、entityManagerが @RequestScoped として生成されていると仮定します)。

@Provider
public class OtherTestFilter implements ContainerRequestFilter {

    @Inject
    EntityManager entityManager;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        Session session =  (Session) entityManager.getDelegate();
        System.out.println(session.hashCode());
    }
} 

これにより、フィルターによって処理されるすべての要求に対してセッションの異なるハッシュ値が得られます。したがって、ここでは理論と実践が一致します。

于 2013-07-28T18:54:24.927 に答える
0

JAX-RS 2 フィルターにはどのようなスコープがありますか?

フィルターなどのプロバイダーは、デフォルトでシングルトンです。


ドキュメントの内容

Applicationドキュメントから:

リソース クラス インスタンスのデフォルトのライフサイクルは、リクエストごとです。プロバイダ (直接または機能を介して登録) のデフォルトのライフサイクルはシングルトンです。

JAX-RS仕様から:

デフォルトでは、JAX-RS アプリケーションごとに、各プロバイダー クラスの 1 つのインスタンスがインスタンス化されます。最初にコンストラクターが呼び出され、次に要求された依存関係が注入され、次に適切なプロバイダー メソッドが複数回 (同時に) 呼び出され、最後にオブジェクトがガベージ コレクションに使用できるようになります。

また、JAX-RS 仕様では、CDI 統合に関して次のことも言及されています。

プロバイダーとApplicationサブクラスは、シングルトンであるか、アプリケーション スコープを使用する必要があります。

于 2018-06-25T15:41:23.073 に答える
0

それが定義されている方法は、DependentScoped のように見えます。他の唯一の可能性はサイレント RequestScoped ですが、それはあまりありそうにありません。

于 2013-07-28T00:48:25.237 に答える