Guice的层次依赖关系

时间:2012-07-02 22:50:07

标签: java jpa guice

我正在努力找出处理以下情况的最佳做法:

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注释。有办法吗?

1 个答案:

答案 0 :(得分:2)

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

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

首先使用重写的bind()方法将绑定器包装在代理中,以拦截EntityManager.class绑定。 (BinderProxy实现Binder并将每个调用传递给它的构造函数中给出的Binder。Source available 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"));

然后向模块添加一个provide方法,该方法在使用EntityManager之前确保Jpa init

@Provides EntityManager provideEm(MyJpaInitializer init, @DefaultEntityManager EntityManager em){
  return em;
}