我有一个类Property<T>
,我想在应用程序启动后绑定它。 Property<T>
表示T
类型的属性,其值可以在运行时修改。
我有可以这样注入的类:
public class MyClass {
public MyClass(@Named("someName") Property<String> property) {
...
}
}
我可以绑定这些实例,但只有在我的应用程序启动后,我才需要知道所有Named
注释值。
我已开始查看Elements
并访问所有Element
个实例以查找其所有Binding
个。获得Bindings
后,我可以使用InjectionPoint.forConstructor()
来获取构造函数。
困扰我的是各种类型的绑定都有它们的区别。我必须处理访问LinkedKeyBinding
,UntargettedBinding
等。
是否有更简单的方法来获取给定模块列表的所有InjectionPoint
?或者也许我会犯这个错误?
谢谢!
答案 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