java - Guice 多注解

标签 java guice

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

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

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

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

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

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

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

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

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

谢谢大家。

最佳答案

正如 Amit 所说,您不能将多个 @BindingAnnotation 应用于任何给定的注入(inject)。在内部,Guice 的工作方式类似于 Map<Key, Provider>其中 Key 是一个可能参数化的类,带有一个可选的单个注释实例。但是,因为这些是实例,欢迎您使用 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 。)相等的注释定义为 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 ,当你可以像注入(inject)注解一样调用注解时,但是如何为 Names.named 这样的实例创建工厂方法呢? ?为此,您需要执行以下操作之一:

  1. Create an anonymous implementation ,每个属性的访问器以及 equals 的正确实现和 hashCode .请注意 hashCode契约(Contract)是much stricter than for Object , 但您可以从 Apache annotation utils 获得兼容的实现或类似的库。
  2. 使用AnnotationLiteral , 它提供了 equalshashCode任意子类的实现。
  3. 使用Google Auto或类似的代码生成器为您生成兼容实现的代码。熟悉这种类型的解决方案对于 Android 和其他反射速度慢的内存受限环境特别有用,尽管此类环境通常会阻止您使用 Guice。 (尽管如此,@Qualifier 注释在其他 JSR-330 兼容依赖注入(inject)框架中的工作方式相同,包括 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();
    } // ...
  }
}

关于java - Guice 多注解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39604399/

相关文章:

java - 使用 Guice 注入(inject) Map 的值

java - 如何扫描类的注解?

java - Apache POI 数据透视表 : Distinct count (Excel 2013)

java - 在 Google Guice 中使用参数执行函数

java - Hibernate:为 ElementCollection 表创建索引

java - 流损坏异常 - 无效代码类型 AC [java]

java - 使用 Guice 设置属性的正确方法是什么?

java - GWT Guice/Gin 在服务器端的问题

java - Hibernate 5.2 在我的表 postgres 上级联删除

java - 在 java 或 python 中动态着色输出到控制台