我正在努力找出处理以下情况的最佳做法:
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注释。有办法吗?
答案 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;
}