Guice 多注解

Guice multiple annotations

我有一个名为 StatsStore 的界面。我有这家商店的 2 个实现。内存中和 SQL 实现称为 InMemoryStatsStoreSqlStatsStore。为了注入它们,我创建了 2 个注释 @InMemoryStore@SqlStore。注射是:

bind(StatsStore.class)
    .annotatedWith(InMemoryStore.class)
    .to(InMemoryStatsStore.class);

bind(StatsStore.class)
    .annotatedWith(SqlStore.class)
    .to(SqlStatsStore.class);   

现在我想添加一层新的注释来分隔 InMemoryStringStoreInMemoryNumberStore 但我不能在绑定行中添加多个注释,例如以下不编译:

bind(StatsStore.class)
    .annotatedWith(InMemoryStore.class)
    .annotatedWith(NumberStoreAnnotation.class) // using named doesn't work as well
    .to(InMemoryNumberStore.class);  

如何在不使用单个命名注释的情况下添加多个注释,如果添加的层越多,就会变得非常复杂?

我想到的另一个解决方案是注入两次:

bind(StatsStore.class)
    .annotatedWith(InMemoryStore.class)
    .to(InMemoryStatsStore.class);

 bind(InMemoryStatsStore.class)
    .annotatedWith(NumberStoreAnnotation.class)
    .to(InMemoryNumberStore.class);

谢谢大家。

can't do that:

@BindingAnnotation tells Guice that this is a binding annotation. Guice will produce an error if ever multiple binding annotations apply to the same member.

您可以改为使用命名绑定,或者您应该考虑重新设计您的解决方案。

正如 Amit 所说,您不能将多个 @BindingAnnotation 应用于任何给定的注入。在内部,Guice 的工作方式类似于 Map<Key, Provider>,其中 Key 是可能参数化的 class,带有可选的单个注释实例。但是,因为这些是 个实例 ,欢迎您使用 create your own instantiable annotation,它的工作方式与 Named 相同。

@Inject @InMemoryStore(NUMBER) StatsStore inMemoryNumberStore;
@Inject @SqlStore(STRING) StatsStore sqlStringStore;
// or
@Inject @Store(dataType=NUMBER, backend=SQL) sqlNumberStore;

注解必须像这样定义字段。 (如果您有一个名为 value 的元素,则可以省略 属性 名称 per JLS 9.7.3.) Equal annotations are defined as in the Annotation.equals docs

public enum DataType { NUMBER, STRING; }
public enum Backend { SQL, IN_MEMORY; }

@BindingAnnotation @Retention(SOURCE) @Target({ FIELD, PARAMETER, METHOD })
public @interface Store {
  DataType dataType();
  Backend backend();
}

这对 @Provides 非常有效,因为您可以像注入注解一样调用注解,但是如何为 Names.named 这样的实例创建工厂方法?为此,您需要执行以下操作之一:

  1. Create an anonymous implementation, with accessors for each attribute as well as correct implementations of equals and hashCode. Note that the hashCode contract is much stricter than for Object, but you can get compatible implementations from Apache annotation utils 或类似的库。
  2. 使用 AnnotationLiteral,它为任意子 classes 提供 equalshashCode 实现。
  3. 使用 Google Auto 或类似的代码生成器为您生成兼容实现的代码。熟悉这种类型的解决方案对于 Android 和反射速度慢的其他内存受限环境特别有用,尽管此类环境通常会阻止您使用 Guice。 (@Qualifier 注解在其他 JSR-330 兼容依赖注入框架中的工作方式相同,包括 Dagger。)

如果上面的看起来有点复杂,或者如果你想要比 Guice 的基于映射的实现更复杂的逻辑,一个替代方法是添加一个你控制的间接层:

public class StoreStore {
  @Inject Provider<InMemoryNumberStore> inMemoryNumberStoreProvider;
  // ...
  // You can also inject the Injector to call getInstance with a class literal.

  public StatsStore getStore(DataType dataType, Backend backend) {
    // This can also be a switch or any other sort of lookup, of course.
    if (dataType == NUMBER && backend == IN_MEMORY) {
      return inMemoryNumberStoreProvider.get();
    } // ...
  }
}