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

这是一个有趣的案例。通常在这样的场景中,您可以将初始化程序绑定在正常的 Singleton 范围内并将其注入到 Dao 实现中,这将确保它在使用 Dao 之前完成。由于 Jpa 持久性模块的设置方式,似乎没有一种简单的方法可以添加此依赖项。

正如 OP 向我指出的那样,JpaPersistModule 是最终的,所以我们不能通过继承它来解决这个问题。但是,我们可以包装用于安装 JpaPersistModule 的活页夹。

首先使用重写的 bind() 方法将绑定器包装在代理中以拦截 EntityManager.class 绑定。(BinderProxy 实现 Binder 并将每个调用传递给它的构造函数中给定的 Binder。源可用here

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 之前进行 Jpa init

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