java - Guice 注入(inject)基于注解值

标签 java annotations guice inject

我想使用 goolge/guice 根据我提供的带有注释的类注入(inject)一个值。

AutoConfig 注释

@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.PARAMETER, ElementType.FIELD })
public @interface AutoConfig {
    // default null not possible
    Class<? extends Provider<? extends ConfigLoader<?>>> provider() default XMLAutoConfigProvider.class;
}

这是我的注释,它允许配置应该用于注释字段的配置类型。

用例:

@AutoConfig()
ConfigLoader<?> defaultConfig;

@AutoConfig(provider = JsonConfigProvider)
ConfigLoader<?> jsonConfig;

我想要两个配置,一个是 default/xml,一个是 json。它们可能永远不会同时出现在同一个类(class)中。但是我不知道什么时候使用一个或另一个。我将这种方法与类一起使用,因为它们是由一些依赖项/库提供的,并且此注释将用于某些(可插入的)子模块。

MyGuiceModule

public class MyGuiceModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(new TypeLiteral<ConfigLoader<?>>() {})
            .annotatedWith(AutoConfig.class)
            .toProvider(autoConfig.provider());
    }
}

这是关键部分,我无法想象如何实现它。

所以基本上我只想使用注释中指定的提供程序类。 也没有必要在这里使用提供者类。因为 autoConfig.provider().newInstance() 基本上是我所需要的。 (我需要在新实例上使用 setter,但这就是我想在这个地方做的所有事情)

总而言之,我真正想做的就是使用 get(AutoConfig autoConfig) 或在构造函数中将注释(或其值推送给提供者)。 目前我只使用构造函数注入(inject)我想在新生成的配置实例上设置的 configFile 值。

最佳答案

如果你知道@AutoConfig(provider = JsonConfigProvider) ConfigLoader<?> jsonConfig将准确返回给您 jsonConfigProvider.get() 的结果,并且 JsonConfigProvider 显然有一个公共(public)无参数构造函数 newInstance工作,你为什么不直接要一个 JsonConfigProvider首先?

从根本上说,Guice 只是一个 Map<Key, Provider>精美的包装。坏消息是,这使得像“为所有 T 绑定(bind) Foo<T>”这样的变量绑定(bind)无法简洁地表达,这包括您的“为所有 T 绑定(bind) @Annotation(T) Foo”。好消息是您还有两个选择。

分别绑定(bind)每个提供者

虽然您无法在提供期间检查注释(或告诉 Guice 为您这样做),但 Guice 将使用它们的 equals 来比较注释。方法,如果你绑定(bind)一个注解 instance 而不是一个注解 class (你会用 Names.named("some-name") 的方式)。这意味着您可以绑定(bind) ConfigLoader<?>与模块中的每个预期注释。当然,这也意味着您必须在配置时有一个可用的 ConfigLoader Provider 列表,但如果您将它们用作注释参数,它们无论如何都必须是编译时常量。

此解决方案也适用于构造函数注入(inject),但对于字段,您需要 @Inject@AutoConfig(...) , AutoConfig 将需要保留其 @BindingAnnotation元注释。

为此,您将不得不编写注释的实现,就像 Guice 处理 NamedImpl 的方式一样。 .请注意 equals 的实现和 hashCode必须与 Java 在 java.lang.Annotation 中提供的匹配.那么这只是一个(冗余)绑定(bind)的问题:

for(Class<ConfigLoader<?>> clazz : loaders) {
  bind(ConfigLoader.class).annotatedWith(new AutoConfigImpl(clazz))
      .toProvider(clazz);
}

equals的定义由您决定,这意味着您可以(并且应该)绑定(bind) @AutoConfig(ConfigEnum.JSON)并在您的模块中保留 Guice 绑定(bind),而不是在整个代码库中指定您请求的实现。

使用自定义注入(inject)

您还可以使用 custom injections在你的注入(inject)类型中搜索自定义注释,如 @AutoConfig .此时,您将使用 Guice 作为平台 来解释 @AutoConfig 而不是 @Inject ,这意味着构造函数注入(inject)将不起作用,但您可以根据注入(inject)的实例、字段名称、字段注释、注释参数或其任意组合来控制注入(inject)。如果选择这种款式,可以滴@BindingAnnotation来自 AutoConfig。

使用 the wiki article linked above 中的示例作为您的模板,但您至少需要:

  1. 使用bindListener在 Binder 或 AbstractModule 上匹配需要此自定义注入(inject)的类型。
  2. 在您绑定(bind)的 TypeListener 中,搜索 @AutoConfig 的注入(inject)类型- 带注释的字段,如果它们有任何匹配的方法,则将这些匹配的方法绑定(bind)到 MembersInjector 或 InjectionListener。您可能希望从此处的注释实例中提取类文字,并将 Field 和 Class 作为构造函数参数传递给 MembersInjector/InjectionListener。
  3. 在您编写的 MembersInjector 或 InjectionListener 中,实例化提供者并将字段设置为提供者提供的实例。

这是一个非常强大的功能,它进一步允许您——例如——根据您要注入(inject)的实例或根据字段名称自动提供配置。但是,请小心使用它并大量记录它,因为 Guice 提供的注释不是 @Inject 可能会让您的同事违反直觉。 .还要记住,这不适用于构造函数注入(inject),因此从字段注入(inject)重构为构造函数注入(inject)将导致 Guice 提示它缺少实例化类所需的绑定(bind)。

关于java - Guice 注入(inject)基于注解值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28549549/

相关文章:

java - 释放 JavaFX 资源

generics - Guice 类型 Kotlin 中的字面量

java - Guice + Tomcat 潜在的内存泄漏

java - Guice:如何为所有类型绑定(bind)泛型?

java - MongoDB 避免在 POJO 中保留某些字段 - Java

java - 如何在调用 Intent 时保持 MainActivity 运行?

java - gwt-maven-插件 : Only generate necessary js files

java - @AutoAnnotation 有什么用?怎么可以用呢?

scala - 如何使用 Scala 和 JUnit 4 设置预期异常

java - 我缺少哪些 Hibernate 注释?