使用guice动态注入通用对象

时间:2018-02-11 16:02:41

标签: java guice

我目前的情况:

我想将以下类注入我的应用程序:

public interface IConfigAccessor<T extends IConfig> {
    ...
}

ConfigAccessor是在运行时动态创建的代理对象。这些对象的创建工作如下:

public class ConfigFactory implements IConfigFactory {
    private final IConfigUpdater updater;

    @Inject
    public ConfigFactory(IConfigUpdater updater) {
        this.updater = updater;
    }

    @Override
    public <T extends IConfig> IConfigAccessor<T> register(final String configKey, final Class<T> configClass) {    
        ConfigCache<T> configCache = new ConfigCache<>(new SomeOtherThings(), configKey, configClass);      
        updater.register(configCache);

        return new ConfigAccessor<>(configCache, configKey, configClass);
    }
}

如您所见,要创建这些对象,我需要注入ConfigUpdater和其他依赖项。这意味着,需要完全配置guice。

要从Guice中获取实例,我使用以下代码:

IConfigFactory configClient = injector.getInstance(IConfigFactory.class);
IConfigAccessor<ConcreteConfig> accessor = configClient.register("key", ConcreteConfig.class)

我想如何通过Guice注入它们:

目前,我可以获得所需的对象,但我必须在我的应用程序中手动传递它们。

相反,我想要的是以下内容:

public class SomeClass {
    @Inject
    public SomeClass(@Config(configKey="key") IConfigAccessor<ConcreteConfig> accessor) {
        // hurray!
    }
}

使这项工作的正确方法/技术是什么?

经过大量的研究,我对如何处理这个话题感到有点迷茫。 Guice提供了许多不同的功能,包括简单的Providers,自定义Listeners,可以扫描类并识别自定义注释,FactoryModuleBuilders等等。

我的问题非常具体,我不确定使用哪些内容以及如何使其正常运行。我甚至不确定Guice是否可以做到这一点?

编辑:到目前为止我有什么

我想在构造函数参数中使用以下注释:

@Target({ ElementType.FIELD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectConfig {
    String configKey();
}

在模块内部,我可以将提供者绑定到IConfigAccessor(带有上述注释),如下所示:

bind(IConfigAccessor.class).annotatedWith(InjectConfig.class)
    .toProvider(new ConfigProvider<>());

然而,这有两个问题:

  1. 提供商无法提供IConfigAccessor。要创建这样的实例,提供者需要IConfigUpdater,但由于我使用'new'作为提供者,我无法注入它。
  2. 在提供商内部,无法找到注释中使用的configKey
  3. 第二种方法:

    假设我已经知道我想在启动期间注入的所有配置和configKeys。在这种情况下,我可以遍历所有可能的configKeys并具有以下绑定:

    String configKey = "some key";
    final Class<? extends IConfig> configClass =...;      
    bind(IConfigAccessor.class).annotatedWith(Names.named(configKey))
        .toProvider(new ConfigProvider<>(configKey, configClass));
    

    然而,问题(1)仍然存在:提供者无法获得IConfigUpdater实例。

1 个答案:

答案 0 :(得分:1)

这里的主要问题是你不能在注射中使用注释的值。还有另一个问题涉及这一部分: Guice inject based on annotation value

您应该绑定提供程序类,而不是绑定提供程序实例,并按injecting a typeliteral获取该类。

这样,您的配置工厂可能看起来像这样:

public class ConfigFactory<T extends IConfig> implements IConfigFactory {
    @Inject private final IConfigUpdater updater;
    @Inject private TypeLiteral<T> type;
    @Override
    public IConfigAccessor<T> register(final String configKey) {    
        Class<T> configClass = (Class<T>)type.getRawType();
        ConfigCache<T> configCache = new ConfigCache<>(new SomeOtherThings(), configKey, configClass);      
        updater.register(configCache);

        return new ConfigAccessor<>(configCache, configKey, configClass);
    }
}

然后是SomeClass:

public class SomeClass {
    @Inject
    public SomeClass(ConfigFactory<ConcreteConfig> accessor) {
        ConcreteConfig config = accessor.register("key");
    }
}

因为SomeClass需要知道&#34; key&#34;无论如何,这不是一个信息变化太多的变化。缺点是SomeClass API现在获得工厂而不是具体的配置。

[编辑]

here实际上是使用自定义注入注入注释值的人。