【问题标题】:Hierarchical Dependencies with GuiceGuice 的分层依赖
【发布时间】:2012-07-02 22:50:06
【问题描述】:

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

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

【问题讨论】:

    标签: java jpa guice


    【解决方案1】:

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

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

    首先将绑定器包装在代理中,并使用重写的 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"));
    

    然后在你的模块中添加一个提供方法,以确保在使用 EntityManager 之前进行 Jpa 初始化

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

    【讨论】:

    • 也刚刚注意到添加到上述问题的答案。看起来不错,不需要我的任何包装愚蠢!
    猜你喜欢
    • 1970-01-01
    • 2011-12-09
    • 1970-01-01
    • 1970-01-01
    • 2016-10-19
    • 1970-01-01
    • 1970-01-01
    • 2011-01-02
    • 1970-01-01
    相关资源
    最近更新 更多