Dependency injection Guice多个实现,带依赖项的参数化构造函数
我正在努力解决一个特殊的依赖注入问题,但我似乎无法解决它。仅供参考:我是guice的新手,但我有其他DI框架的经验——这就是为什么我认为这不应该太复杂而难以实现的原因 我在做什么: 我正在从事Lagom多模块项目,并使用Guice作为DI 我希望达到的目标是: 将某些接口实现的多个命名实例(我们称之为publisher,因为它会将消息发布到kafka主题)注入到我的服务中。 这个“发布者”已经注入了一些Lagom和Akka相关的服务(ServiceLocator、ActorSystem、Materializer等) 现在,我希望有两个这样的发布者实例,每个实例将消息发布到不同的主题(因此每个主题有一个发布者实例) 我将如何实现这一点? 我对同一主题的一个或多个实例没有问题,但是如果我想为每个实例注入不同的主题名称,我就有问题了 因此,我的publisher实现构造函数如下所示:Dependency injection Guice多个实现,带依赖项的参数化构造函数,dependency-injection,guice,lagom,Dependency Injection,Guice,Lagom,我正在努力解决一个特殊的依赖注入问题,但我似乎无法解决它。仅供参考:我是guice的新手,但我有其他DI框架的经验——这就是为什么我认为这不应该太复杂而难以实现的原因 我在做什么: 我正在从事Lagom多模块项目,并使用Guice作为DI 我希望达到的目标是: 将某些接口实现的多个命名实例(我们称之为publisher,因为它会将消息发布到kafka主题)注入到我的服务中。 这个“发布者”已经注入了一些Lagom和Akka相关的服务(ServiceLocator、ActorSystem、Mate
@Inject
public PublisherImpl(
@Named("topicName") String topic,
ServiceLocator serviceLocator,
ActorSystem actorSystem,
Materializer materializer,
ApplicationLifecycle applicationLifecycle) {
...
}
如果我想创建一个实例,我会在我的ServiceModule中这样做:
public class FeedListenerServiceModule extends AbstractModule implements ServiceGuiceSupport {
@Override
protected void configure() {
bindService(MyService.class, MyServiceImpl.class);
bindConstant().annotatedWith(Names.named("topicName")).to("topicOne");
bind(Publisher.class).annotatedWith(Names.named("publisherOne")).to(PublisherImpl.class);
}
}
如何为每个主题绑定多个发布者
我在玩另一个私有模块的实现:
public class PublisherModule extends PrivateModule {
private String publisherName;
private String topicName;
public PublisherModule(String publisherName, String topicName) {
this.publisherName = publisherName;
this.topicName = topicName;
}
@Override
protected void configure() {
bindConstant().annotatedWith(Names.named("topicName")).to(topicName);
bind(Publisher.class).annotatedWith(Names.named(publisherName)).to(PublisherImpl.class);
}
}
但这让我一事无成,因为您无法在模块配置方法中获取喷油器:
Injector injector = Guice.createInjector(this); // This will throw IllegalStateException : Re-entry is not allowed
injector.createChildInjector(
new PublisherModule("publisherOne", "topicOne"),
new PublisherModule("publisherTwo", "topicTwo"));
唯一简单有效的解决方案是,我将PublisherImpl改为abstract,添加抽象的“getTopic()”方法,并添加另外两个具有主题覆盖的实现
但这一解决方案是站不住脚的。为代码重用添加额外的继承并不完全是最佳实践。而且我相信Guice肯定会支持这种特性
欢迎任何建议。
KR,NejcGuice的依赖注入方法是DI框架补充了您的实例化逻辑,而不是取代它。在可能的情况下,它会为您实例化一些东西,但它不会试图在这方面做得太聪明。它也不会混淆配置(主题名称)和依赖项注入——它只做了一件事,DI,而且做得很好。所以你不能用它来配置东西,比如用Spring 因此,如果你想用两个不同的参数实例化一个对象,那么你就用两个不同的参数实例化这个对象——也就是说,你调用
new
两次。这可以通过使用提供程序方法来实现,这些方法记录在此处:
在您的情况下,可能类似于将以下方法添加到模块中:
@Provides
@Named("publisherOne")
@Singleton
Publisher providePublisherOne(ServiceLocator serviceLocator,
ActorSystem actorSystem,
Materializer materializer,
ApplicationLifecycle applicationLifecycle) {
return new PublisherImpl("topicOne", serviceLocator,
actorSystem, materializer, applicationLifecycle);
}
此外,如果您正在添加生命周期挂钩,您可能希望它是一个单例,否则每次您在实例化一个新挂钩时都会遇到内存泄漏。Guice的依赖项注入方法是DI框架补充您的实例化逻辑,而不是取代它。在可能的情况下,它会为您实例化一些东西,但它不会试图在这方面做得太聪明。它也不会混淆配置(主题名称)和依赖项注入——它只做了一件事,DI,而且做得很好。所以你不能用它来配置东西,比如用Spring 因此,如果你想用两个不同的参数实例化一个对象,那么你就用两个不同的参数实例化这个对象——也就是说,你调用
new
两次。这可以通过使用提供程序方法来实现,这些方法记录在此处:
在您的情况下,可能类似于将以下方法添加到模块中:
@Provides
@Named("publisherOne")
@Singleton
Publisher providePublisherOne(ServiceLocator serviceLocator,
ActorSystem actorSystem,
Materializer materializer,
ApplicationLifecycle applicationLifecycle) {
return new PublisherImpl("topicOne", serviceLocator,
actorSystem, materializer, applicationLifecycle);
}
另外,如果您正在添加生命周期挂钩,您可能希望它是一个单例,否则每次您在实例化新挂钩时都可能会遇到内存泄漏。不要在配置方法中创建新的注入器。相反,您创建的新模块。无需子注入器,如文档中所述,“专用模块使用父注入器实现”,因此无论如何都会涉及子注入器
install(new PublisherModule("publisherOne", "topicOne"));
install(new PublisherModule("publisherTwo", "topicTwo"));
在这种情况下,您使用PrivateModule的技术就是我要使用的技术,特别是考虑到您希望通过绑定注释提供绑定,尤其是在运行时知道完整的主题集的情况下。您甚至可以在循环中调用install
但是,如果需要任意数量的实现,则可能需要创建一个可注入工厂或提供程序,以便在运行时向其传递字符串集
public class PublisherProvider {
// You can inject Provider<T> for all T bindings in Guice, automatically, which
// lets you configure in your Module whether or not instances are shared.
@Inject private final Provider<ServiceLocator> serviceLocatorProvider;
// ...
private final Map<String, Publisher> publisherMap = new HashMap<>();
public Publisher publisherFor(String topicName) {
if (publisherMap.containsKey(topicName)) {
return publisherMap.get(topicName);
} else {
PublisherImpl publisherImpl = new PublisherImpl(
topicName, serviceLocatorProvider.get(), actorSystemProvider.get(),
materializerProvider.get(), applicationLifecycleProvider.get());
publisherMap.put(topicName, publisherImpl);
return publisherImpl;
}
}
}
公共类发布者提供者{
//您可以在Guice中自动为所有T绑定注入提供程序,这
//允许您在模块中配置实例是否共享。
@注入私有最终提供者ServiceLocator提供者;
// ...
private final Map publisherMap=new HashMap();
公共发布者发布者(字符串topicName){
if(publisherMap.containsKey(主题名称)){
返回publisherMap.get(topicName);
}否则{
PublisherImpl PublisherImpl=新的PublisherImpl(
topicName、serviceLocatorProvider.get()、actorSystemProvider.get(),
MaterialierProvider.get(),applicationLifecycleProvider.get();
publisherMap.put(主题名,publisherImpl);
返回RIMPL;
}
}
}
您可能希望使上述线程安全;此外,您可以通过使用()或()避免显式构造函数调用,这将在注入像ServiceLocator这样的DI提供者时自动传递像topicName这样的显式参数(希望这有一个特定的目的,因为您可能不需要在DI框架中进行太多的服务定位!)
(边注:不要忘记为您的私有模块注释您的绑定。如果您没有发现自己在任何地方注入您的<代码> TopICNEX/CODE,您也可以考虑使用辅助代码注入或自动填充器使用个人<代码> @提供< /COD>方法。