通过注释动态生成注入

时间:2015-10-12 18:33:25

标签: guice

假设我有一个类似这样的类:

public class MyClass {
    @Inject
    public MyClass(@Foo("whatever") Bar dependency) {
        // ...
    }
}

我希望有一些自定义逻辑,可以看到我们正在注入一个类型为Bar的对象,注释类型为@Foo("whatever"),并构造一个相应的Bar对象...类似于Guice Provider,但这会获得有关注射部位的更多上下文信息。 Guice让我做那样的事吗?

1 个答案:

答案 0 :(得分:3)

通过普通Guice无法实现您所描述的内容:提供者旨在成为零参数纯函数,并且无法像将灵活的回调函数那样将注入站点信息转换为它们。

您可以通过两种不同的方式估算出您想要的内容:

  • 如果您知道 @Foo参数的每个可能值,您可以将@Foo设为binding annotation并通过提供来绑定它一个Annotation-compatible equals and hashCode。这提供了最直观的体验:您可以使用@Foo对任何其他类型执行任何操作,例如在构造函数中使用@Foo或注入@Foo("value") Provider<Bar> barProvider

    @Override public void configure() {
      for (String value : PREDEFINED_VALUES) {
        bind(Bar.class)
            .annotatedWith(new FooImpl(value))
            .toProvider(new BarProvider(value));
      }
    }
    
  • 如果您希望@Foo适用于任意参数,则需要使用custom injections扩展Guice。这不适用于构造函数注入或与任何其他@Inject注释一起使用,但它允许您在Guice注入完成后检查类型以根据需要增加它们(例如,检测并响应@Foo字段上的注释)。

    有关详细信息,请参阅the example in the Guice docs

在内部,Guice的核心实际上是Map<Key, Provider>,其中Key表示一对可能参数化的类型和可选的绑定注释。之前的绑定注释技巧很有效,因为Guice可以将注入请求全部映射到Provider,后者跳过Guice的映射,这样您就可以自己检查/构造/注入实例。

如果您愿意跳过解决方案的注释部分,可以注入一个BarProviderBarFactory公开forFoo(String)方法,这样可以在不知道的情况下为您提供一致的注射提前所有的String值。这样您就可以使用assisted injectionAutoFactory生成工厂(如果您希望每次调用生成一个实例),或者让您自己编写一个简单的工厂以增加灵活性。

public class MyClass {
    private final Bar dependency;

    @Inject
    public MyClass(BarProvider barProvider) {
        dependency = barProvider.forFoo("whatever");
        // ...
    }
}