Guice基于注释值注入

ST-*_*DDT 5 java annotations inject guice

我想使用goolge/guice根据我提供的类注释注入一个值.

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;
}
Run Code Online (Sandbox Code Playgroud)

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

用例:

@AutoConfig()
ConfigLoader<?> defaultConfig;

@AutoConfig(provider = JsonConfigProvider)
ConfigLoader<?> jsonConfig;
Run Code Online (Sandbox Code Playgroud)

我想要两个配置,一个默认/ xml一个和一个json.它们可能永远不会同时出现在同一个类中.但我不知道何时使用这一个或另一个.我在类中使用了这个方法,因为它们是由一些依赖项/库提供的,这个注释将用于一些(可插入的)子模块.

MyGuiceModule

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

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

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

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

Jef*_*ica 4

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

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

分别绑定每个提供商

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

该解决方案也适用于构造函数注入,但对于字段,您需要同时使用@Inject@AutoConfig(...),并且 AutoConfig 需要保留其@BindingAnnotation元注释。

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

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

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

使用自定义注入

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

使用上面链接的 wiki 文章中的示例作为模板,但至少您需要:

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

这是一个非常强大的功能,例如,它进一步允许您根据要注入的实例或字段名称自动提供配置。然而,请小心使用它并大量记录它,因为 Guice 提供除@Inject. 另请记住,这对于构造函数注入不起作用,因此从字段注入重构为构造函数注入将导致 Guice 抱怨它缺少实例化类所需的绑定。