4

次の状況に対処するためのベスト プラクティスを見つけようとしています。

public class AppModule extends Module {

  @Override
  protected void configure() {
    install(new JpaPersistModule("myJpaUnit").addFinder(Dao.class));
    bind(MyJpaInitializer.class).asEagerSingleton();
  }

  @Provides
  @IndicatesSomeConstantMap
  @Singleton
  Map<String, String> getMappings(Dao dao) {
    ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<String, String>();
    // Build map from Dao
    return builder.build();
  }

}

@IndicatesSomeConstantMap を他のクラスに注入する必要があります。getMappings が Dao を取得できる唯一の方法は、 MyJpaInitializer を EagerSingleton としてバインドすることです。これは間違っていると感じています。これらの階層的な依存関係を処理するための推奨される方法は何ですか?

編集:

@jeffcrowe からの回答に基づいて、次のようなものを思いつきました。

public class Module1 extends PrivateModule {

  @BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME)
  public @interface Jpa1{}

  @Singleton
  public static class JpaInitializer1 {
    @Inject
    public JpaInitializer1(@Jpa1 PersistService service) {
      service.start();
    }
  }

  public interface Finder1 {
    @Finder(query="FROM Foo", returnAs = ArrayList.class)
    List<Foo> getAll();
  }

  @Override
  protected void configure() {
    install(new JpaPersistModule("firstJpaUnit").addFinder(Finder1.class));
    bind(JpaInitializer1.class);
  }

  @Provides
  @Exposed
  @Jpa1
  PersistService getPersistService(Provider<PersistService> provider) {
    return provider.get();
  }

  @Provides
  @Exposed
  @Jpa1
  Finder1 getFinder(Finder1 finder, JpaInitializer1 init) {
    return finder;
  }

}

これは依存関係をプロバイダーの背後にラップすることで処理し、eagerSingleton アプローチを使用するよりもクリーンに感じます。これにより、プライベート モジュールの背後にある JpaModule も非表示になり、複数の永続性モジュールがバインドされている状況で役立ちます。新しい問題は、Finder がすでに JpaPersistModule によってバインドされているため、Finder1 のすべてのインジェクションに @Jpa1 アノテーションを追加する必要があることです。それを回避する方法はありますか?

4

1 に答える 1

2

これは興味深いケースです。通常、このようなシナリオでは、初期化子を通常のシングルトンスコープでバインドし、それをDao実装に注入できます。これにより、Daoが使用される前に確実に実行されます。Jpa永続化モジュールの設定方法が原因で、この依存関係を追加する簡単な方法はないようです。

OPが私に指摘したように、JpaPersistModuleは最終的なものであるため、サブクラス化してこれを回避することはできません。ただし、JpaPersistModuleのインストールに使用したバインダーをラップすることはできます。

まず、バインダーをプロキシでラップし、bind()メソッドをオーバーライドして、EntityManager.classバインディングをインターセプトします。(BinderProxyはBinderを実装し、そのコンストラクターで指定されたBinderにすべての呼び出しを渡します。ソースはここで入手できます

new BinderProxy(binder()) {
  @Override
  public <T> AnnotatedBindingBuilder<T> bind(Class<T> clazz) {
    if (clazz == EntityManager.class) {
      return (AnnotatedBindingBuilder<T>) super.bind(clazz).annotatedWith(DefaultEntityManager.class);
    } else {
      return super.bind(clazz);
    }
  }
}.install(new JpaPersistModule("myJpaUnit"));

次に、EntityManagerが使用される前にJpainitを保証するprovidesメソッドをモジュールに追加します

@Provides EntityManager provideEm(MyJpaInitializer init, @DefaultEntityManager EntityManager em){
  return em;
}
于 2012-07-06T22:21:45.410 に答える