Guice - 根据定义的InjectionPoints

时间:2016-11-21 01:00:31

标签: java guice

我有一个类Property<T>,我想在应用程序启动后绑定它。 Property<T>表示T类型的属性,其值可以在运行时修改。

我有可以这样注入的类:

public class MyClass {
    public MyClass(@Named("someName") Property<String> property) {
       ...
    }
}

我可以绑定这些实例,但只有在我的应用程序启动后,我才需要知道所有Named注释值。

我已开始查看Elements并访问所有Element个实例以查找其所有Binding个。获得Bindings后,我可以使用InjectionPoint.forConstructor()来获取构造函数。

困扰我的是各种类型的绑定都有它们的区别。我必须处理访问LinkedKeyBindingUntargettedBinding等。 是否有更简单的方法来获取给定模块列表的所有InjectionPoint?或者也许我会犯这个错误?

谢谢!

3 个答案:

答案 0 :(得分:1)

听起来你正试图为所有foo和bar注入auth/facebook并在事后解决它们,而Guice并没有做得特别好。因为Guice配置在运行时发生(@Named(foo) Property<bar>方法必须运行),所以你可以使用Guice的SPI来做你正在做的事情的唯一方法就是预先绑定所有键,以便Guice不会抱怨一个不完整的对象图然后检查它以找出要填充的内容。这似乎是费力和过度工作。

此外,只要Guice允许JIT或&#34;隐含&#34;绑定,你不能知道Guice在请求对象之前可能尝试解决的每个密钥。即使您拥有完美的模块或注入反射库,这也可能难以绑定您需要的所有内容。如果您在创建注射器之前不知道自己需要什么或者可以使用什么,那么您也会绕过Guice的一些依赖关系图验证功能。

虽然它不是Guice的完美理想用法和依赖注入的概念,但我会通过编写configure来调整我的代码:

PropertyOracle

尽管这种类型的规定在某种程度上与Guice重复,但与Guice不同,您可以使用您想要的任何类型或密钥注入属性,然后再解析它 - 可能是异步的。然后你会编写一个伪造的或模拟的PropertyOracle来用于测试,这不像直接注入Property实例那么容易,但它可能是最简单的方法来挂钩请求而没有Guice SPI的复杂性

答案 1 :(得分:1)

我最终使用BindingTargetVisitor来涵盖我需要的用例。

请注意,此解决方案适用于我们的特定用例,但可能对您的用例有限,具体取决于您使用的绑定和注入类型。

public class InjectionPointExtractor extends DefaultBindingTargetVisitor<Object, InjectionPoint> {
  private final Predicate<TypeLiteral<?>> filter;

  public InjectionPointExtractor(Predicate<TypeLiteral<?>> filter) {
    this.filter = filter;
  }

  @Override
  public InjectionPoint visit(UntargettedBinding<?> untargettedBinding) {
    return getInjectionPointForKey(untargettedBinding.getKey());
  }

  @Override
  public InjectionPoint visit(LinkedKeyBinding<?> linkedKeyBinding) {
    return getInjectionPointForKey(linkedKeyBinding.getLinkedKey());
  }

  @Override
  public InjectionPoint visit(ProviderKeyBinding<?> providerKeyBinding) {
    return getInjectionPointForKey(providerKeyBinding.getProviderKey());
  }

  private InjectionPoint getInjectionPointForKey(Key<?> key) {
    if (filter.test(key.getTypeLiteral())) {
      return InjectionPoint.forConstructorOf(key.getTypeLiteral());
    }

    return null;
  }
}

我们使用filter仅过滤我们的包中定义的类。这样可以以一种漂亮而干净的方式完成工作。

如果您不使用@Inject构造函数,而是使用Guice直接设置字段,则可以使用TypeListener

答案 2 :(得分:0)

我们假设注释是声明性的,并且您的Property注射的最终计数。因此,您可以在应用程序启动时扫描它并创建所有绑定。

我创建了一个自定义注释 - 让我们说Configuration Property字段(它可以只是值)。 我为配置注释创建了一个类路径扫描程序,并为每个Provider注册Configuration

然后它看起来像:

你的装订:

public class MyClass {
    public MyClass(@Configuration("someName") Property<String> property) {
       ...
    } }

您的模块:

ClasspathScanner classpathScanner = new ClasspathScanner(
    Arrays.asList("com.example"),
    Lists.newArrayList());

    List<Configuration> configurations = classpathScanner.getClasses().
        stream().
        filter(c -> find consturctors with Configuration annotation).
        collect(Collectors.toList());

    configurations.forEach(e -> bind(Key.get(String.class,e)).toProvider(new PropertyStringProvider(e.value())));

您的提供者:

public class PropertyStringProvider implements Provider<String> {

  private final String propertyName;      

  public PropertyStringProvider(String propertyName) {
    this.propertyName = propertyName;
  }

  @Override
  public String get() {
    return //find property for given name. Best to use Archaius framework
  }
}

嗯,这个建议的灵感来自基于guice的州长框架。 https://github.com/Netflix/governator/wiki/Configuration-Mapping