2

Guava を使用しEventBusてパブリッシュ/サブスクライブ メッセージング サービスを作成しています。また、初めて Guice を使用しようとしています。私は Guice のチュートリアルを読んで、AbstractModuleBinderクラスで遊んでいます。しかし、チュートリアルを終了して、自分のプロジェクトで実際に何かを機能させようとすると、窒息してしまいます。

私のプロジェクトにはEventMonitor、 Guice が注入された Guava のインスタンスを持つ がありますEventBus

public class EventMonitor {
    @Inject
    private EventBus guavaEventBus;

    // ...
}

アプリケーションの Guice/DI/Bootstrapping コードで、concretion を定義しますAbstractModule

public class MyAppModule extends AbstractModule {
    @Override
    public void configure() {
        // Here is where I want to wire together the EventBus to give
        // to the EventMonitor.
    }
}

最終的には、EventBus通常は次のように (非 Guice コードで) 構築されるようにしたいと思います。

ThreadFactory factory = ThreadManager.currentRequestThreadFactory();
Executor executor = Executors.newCachedThreadPool(factory)
EventBus eventBus = new AsyncEventBus(executor);

と の 2 つの (一見インジェクトでき​​ないように見える) 静的メソッドThreadManagerExecutors、私の参照は an 用ですEventBusが、実際のオブジェクトはAsynEventBus;であるため、窒息しています。したがって、それをバインドする方法がわかりません:

// Doesn't work because how does Guice know I'm referencing an AsyncEventBus?!?
bind(EventBus.class).toInstance(executor);

// Doesn't work because now I've lost the ability to pass the
// AsyncEventBus an 'executor' and no-arg ctor is used!
bind(EventBus.class).to(AsyncEventBus.class);

だから私は尋ねます:私が自分の を構築したい方法を考えると、完全に構成されたが適切に注入されるEventBusように、戦闘で使い古された Guice のベテランがここに ( 、 、 を使用して) どのように配線するのThreadFactoryでしょExecutorEventBusか? このより「複雑な」例を見ると、木を通して森を見始めると思います。前もって感謝します。EventMonitorEventBus

4

1 に答える 1

6

戦場で使い古された Guice のベテランは、どうやってここに物事を配線するのでしょうか?

2 つの言葉: プロバイダー メソッド。

public class MyAppModule extends AbstractModule {
    @Override
    public void configure() {
        bind(EventBus.class).to(AsyncEventBus.class);
    }

    @Provides @Singleton
    ThreadFactory providesThreadFactory() {
        return ThreadManager.currentRequestThreadFactory();
    }

    @Provides @Singleton
    Executor providesExecutor(ThreadFactory factory) {
        return Executors.newCachedThreadPool(factory)
    }

    @Provides @Singleton
    AsyncEventBus providesAsyncEventBus(Executor executor) {
        return new AsyncEventBus(executor);
    }
}

「provides」で始まるメソッドの命名規則は@Provides、Guice が必要とするものではありませんが、特に大規模なコードベースでは、本当にやりたいことです。コード本体から「provides」を検索し、特定のオブジェクトを提供するメソッドを見つけることができる。

コメント内の質問に回答するためのいくつかのメモ:

  • Guice は、メソッドModule用にインストールするすべてのインスタンスを調べ@Provides、メソッドの戻り値の型を.toProvider匿名Providerインスタンスにバインドしたかのようにインストールします。したがって、それらの優れた点は、メソッド内でそれらを使用するために追加のコードを必要としないことですconfigure

  • @Singleton注釈は、そのインスタンスが 1 つだけ必要であることを示しているため、メソッドは 1 回だけ呼び出されますprovides*。オフのままにしておくと、デフォルトでは、インスタンスを注入する必要があるたびに、guice がプロバイダーを呼び出したり、新しいオブジェクトをインスタンス化したりします (そのクラスの構成内容に応じて)。注: 最初にこれを発見したときにびっくりして、「効率のために」どこにでも置きたいと思う人もい@Singletonますが、これは不適切な反応です。実際には、@Singleton複数の異なるインスタンスを持つことが不適切な場合にのみ、慎重に使用する必要があります。

    この場合、周囲に 1 つしかないことを確認したいと考えていEventBusます。他のクラスに直接注入しExecutorたりThreadFactory、他のクラスに注入したりしない限り、それらのメソッドから注釈を残すことができます。とにかく呼び出されるたびに同じインスタンスを返すThreadFactoryと思うので、これはほぼ確実に違いはありません。ThreadManager.currentRequestThreadFactory()には違いがありますが、それを使用している他の場所でExecutor新しいインスタンスが必要になる可能性がありますか?Executor

  • メソッドへのパラメーターは@Provides、残りの構成と同じ方法で接続されます。たとえば、この場合、によって返されたprovidesAsyncEventBusが取得されることがわかっています。次のような 2 つの方法があるとします。ExecutorprovidesExecutorExecutor

    @Provides @Singleton
    Executor providesExecutor1(ThreadFactory factory) {
        return Executors.newCachedThreadPool(factory)
    }
    
    @Provides @Singleton
    Executor providesExecutor2(ThreadFactory factory) {
        return Executors.newScheduledThreadPool(10, factory)
    }
    

    次に、インジェクターを作成しようとすると、guice は構成エラーをスローします。これは、2 つの異なる方法を使用してExecutor. さて、代わりに次のようなものがあるとします:

    @Provides @Singleton
    ExecutorService providesExecutor1(ThreadFactory factory) {
        return Executors.newCachedThreadPool(factory)
    }
    
    @Provides @Singleton
    ScheduledExecutorService providesExecutor2(ThreadFactory factory) {
        return Executors.newScheduledThreadPool(10, factory)
    }
    

    しかし、それでも上記の方法があった場合、インジェクターを作成しようとすると、必要なprovidesAsyncEventBus作成方法を指示しなかったため、guice はエラーをスローします。次のような追加の行が必要です。ExecutorprovidesAsyncEventBus

    bind(Executor.class).to(ExecutorService.class);
    

    configure問題を解決する方法で。

  • 方法に関してregisterは、いくつかのオプションがあります。私が信じている最も簡単な方法は、登録する必要があるオブジェクトEventBusの注釈付きコンストラクターにパラメーターを追加し、コンストラクターの最後の行として実行することです。@InjectevtBus.register(this)

    他のオプションには、静的注入 (これについては読むことができますが、私はお勧めしません) を使用するか、マルチバインダーを使用して aSet<Object>を適切な注釈にバインドし、次に を作成するのと同じスタートアップ コードで、Injectorそのセットを反復処理して何かを登録することが含まれます。(この 2 番目の方法は、いくつかの適切なパターンで実行できますが、より単純な Guice の使用パターンについて詳しく学ぶまではお勧めしません)

于 2013-02-03T03:05:31.893 に答える