3

私は Guice [v3] で動作する Wicket [v6] アプリケーションを持っています。現在、リポジトリ操作に依存性注入を使用しており、セッション スコープ (ユーザーのセッションごとに 1 つ) のサービスを使用するためにそれを使いたいと考えています。公式ドキュメント、さまざまなブログ投稿、ここでの質問を読みましたが、正しいアプローチを使用しているかどうかはわかりません.

2 つの質問があります: 1. 正しい方法を使用していますか? 2. SessionScoped インジェクションに依存するクラスで TestNG テストを実行するには、何か特別なものが必要ですか?

私のセットアップ: web.xml:

<filter>
    <filter-name>guiceFilter</filter-name>
    <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>    
<filter-mapping>
    <filter-name>guiceFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
    <listener-class>com.xxx.CustomServletConfig</listener-class>

MyApplication 初期化:

@Override
protected void init()
{
    super.init();
    getResourceSettings().setResourcePollFrequency(null);
    getMarkupSettings().setStripWicketTags(true);
    getDebugSettings().setDevelopmentUtilitiesEnabled(true);
    GuiceComponentInjector injector = new GuiceComponentInjector(this, new WebModule(), new GuiceModule());;
}

カスタムサーブレット構成:

public class CustomServletConfig  extends GuiceServletContextListener {

    @Override
    protected Injector getInjector() {
        return Guice.createInjector(new GuiceModule(), new WebModule());
    }

ウェブモジュール:

public static class WebModule extends ServletModule {

    @Override
    protected void configureServlets() {
        bind(WebApplication.class).toProvider(WicketGuiceAppProvider.class).asEagerSingleton();  

        bind(IUserService.class).to(UserService.class).in(ServletScopes.SESSION);

        Map<String, String> params = new HashMap<String, String>();    
        params.put(WicketFilter.FILTER_MAPPING_PARAM, "/*");  

        filter("/*").through(WicketGuiceFilter.class, params);  
    }
}

私が持っているサンプルページでは:

@Inject
IUserService userService

...

userService.doSomething

単体テスト中の userService.doSomething で、ServletModule のバインディングを指している Guice OutOfScopeException を取得しています: カスタム プロバイダーのエラー、com.google.inject.OutOfScopeException?: スコープ オブジェクトにアクセスできません。現在、HTTP サーブレット リクエスト内にいないか、com.google.inject.servlet.GuiceFilter を適用するのを忘れている可能性があります。このリクエストのサーブレット フィルタとして。

構成は問題なく、別の方法で単体テストを実行する必要があります (WicketTester でアプリケーションを起動しているだけです)、または設計に問題がありますか?

4

1 に答える 1

3

これは非常に一般的な障害です。

ServletScopesまたはのすべてのエンティティはRequestScopes、 として渡す必要がありますProviders

したがって、コードは次のようになります。

@Inject
Provider<IUserService> userServiceProvider

public IUserService getUserService() {
  userServiceProvider.get(); 
}

なんでそうなの?!Stage.DEVELOPMENT で使用し、親クラスが積極的に作成されない限り、すべて問題ありません。親クラスを Stage.PRODUCTION としてバインドするか、asEagerSingletonまたは Stage.PRODUCTION に切り替えると、起動時にクラスが熱心に作成され始めます。それ以外の場合、それらはアクセスされたときにのみ遅延して作成されます (最初の要求時に非常に可能性が高い)。

そして、あなたの問題が発生します。WebApplication起動時に熱心に初期化されます。次に、guice はすべての子依存関係を注入しようとし、IUserServiceどれが でフィールド注入であるかを見つけましたSessionScope。問題は、現在 GuiceFilter 内になく、リクエストがないため、guice が現在のセッションを特定したり、新しいセッションを作成したりできないことです。したがって、これらのスコープには到達できません。あなたは現在あなたの中にいてContextListener、あなたのアプリケーションは熱心にインスタンス化されています. 遅延読み込みのSingleton代わりに使用する場合は、すべて問題ありません。asEagerSingleton

とにかく、Session および Request スコープのオブジェクトを Provider として渡すことがベスト プラクティスです。プロバイダーの詳細についてはこちら、スコープの詳細についてはこちらをご覧ください (熱心な読み込みと遅延読み込みを比較した素敵な表もあります)。

于 2013-10-30T10:57:04.790 に答える