Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Guice-基于定义的注入点在运行时将泛型类绑定到实例_Java_Guice - Fatal编程技术网

Java Guice-基于定义的注入点在运行时将泛型类绑定到实例

Java Guice-基于定义的注入点在运行时将泛型类绑定到实例,java,guice,Java,Guice,我有一个类属性,我想在应用程序启动后绑定它Property表示类型为T的属性,其值可以在运行时修改 我有一些可以注入的类: public class MyClass { public MyClass(@Named("someName") Property<String> property) { ... } } 公共类MyClass{ 公共MyClass(@Named(“someName”)属性){ ... } } 我可以绑定这些实例,但只能在应用程序

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

我有一些可以注入的类:

public class MyClass {
    public MyClass(@Named("someName") Property<String> property) {
       ...
    }
}
公共类MyClass{
公共MyClass(@Named(“someName”)属性){
...
}
}
我可以绑定这些实例,但只能在应用程序启动后绑定,并且我需要知道所有名为的注释值


我已经开始查看
元素
并访问所有
元素
实例,以查找其所有
绑定
s。一旦有了
绑定
,我就可以使用
InjectionPoint.forConstructor()
来获取构造函数

困扰我的是,各种类型的绑定都有其不同之处。我必须处理访问
LinkedKeyBinding
UntargetedBinding
,等等。。 对于给定的模块列表,是否有更简单的方法获取所有
注入点
?或者我做错了


谢谢

听起来好像您试图为所有foo和bar注入
@Named(foo)属性
,并在事后解决它们,而Guice做得并不特别好。因为Guice配置是在运行时进行的(必须运行
configure
方法),所以您可以使用Guice的SPI进行操作的唯一方法是预先绑定所有键,这样Guice就不会抱怨对象图不完整,然后检查它以确定填充什么。这似乎很费劲,而且设计过度

此外,只要Guice允许JIT或“隐式”绑定,在请求对象之前,您就无法知道Guice可能尝试解析的每个键。这可能会使绑定所需的所有内容变得困难,即使您有一个完美的模块或注入器反射库。如果您在创建注入器之前不知道需要什么或有什么可用,那么您也可以绕过Guice的一些依赖关系图验证功能

虽然这不是Guice和依赖注入概念的完美使用,但我会通过编写
PropertyOracle
,来调整我的代码:

public class MyClass {
    private final Property<String> someNameProperty;

    public MyClass(PropertyOracle propertyOracle) {
        someNameProperty = propertyOracle.getString("someName");
        // The act of getting tells the oracle which properties to get. You can also
        // separate those steps without holding onto an instance:
        propertyOracle.prepare("keyToBeRequestedLater");
    }
}
公共类MyClass{
私有最终财产someNameProperty;
公共MyClass(PropertyOracle PropertyOracle){
someNameProperty=propertyOracle.getString(“someName”);
//获取的行为告诉oracle要获取哪些属性。您还可以
//在不保留实例的情况下分离这些步骤:
房地产触角准备(“keyToBeRequestedLater”);
}
}

尽管这种类型的规定在某种程度上与Guice重复,但与Guice不同,您可以使用任何类型或键插入属性,然后稍后解析它——可能是异步的。然后编写一个假的或模拟的PropertyOracle用于测试,这不像直接注入属性实例那么容易,但是,这可能是在没有Guice SPI复杂性的情况下连接请求的最简单方法。

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

我将创建一个自定义注释,比如说
配置
带有
属性
字段(它可以只是值)。
我将为配置注释创建一个类路径扫描程序,并为每个
配置注册一个
提供程序

然后它看起来像:

你的约束力:

public class MyClass {
    public MyClass(@Configuration("someName") Property<String> property) {
       ...
    } }
公共类MyClass{
公共MyClass(@Configuration(“someName”)属性){
...
} }
您的模块:

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())));
ClasspathScanner ClasspathScanner=新的ClasspathScanner(
Arrays.asList(“com.example”),
Lists.newArrayList());
列表配置=classpathScanner.getClasses()。
流()。
过滤器(c->使用配置注释查找constructor)。
collect(Collectors.toList());
configurations.forEach(e->bind(Key.get(String.class,e)).toProvider(newpropertyStringProvider(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
  }
}
公共类PropertyStringProvider实现提供程序{
私有最终字符串propertyName;
公共PropertyStringProvider(字符串propertyName){
this.propertyName=propertyName;
}
@凌驾
公共字符串get(){
返回//查找给定名称的属性。最好使用Archaius框架
}
}

这是一个基于guice的Governator框架的建议

我最终使用了一个
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;
  }
}
公共类InjectionPointExtractor扩展了DefaultBindingTargetVisitor{

private final predicate我认为关键在于调用
getDependencies()
在每个
元素上
您可以,然后为您看到的每个
@注释属性
依赖项注册新绑定。我不想使用反射,因为它可能会捕获在Guice中定义但未绑定的类。例如,如果我打开一个库,但只需要它的一些类,我不想要我的应用程序要求我为这个库的所有类定义属性,即使我没有全部使用它们。