Guice配置错误:未绑定任何实现

Rom*_*man 17 java dependency-injection guice

我正在尝试使用Guice工作制作DI,对我来说(在我看来)确实是手册中的内容.

我无法解释这个问题,因为我并不真正理解它 - 一切看起来都非常符合逻辑并应该有效......但事实并非如此.所以,我只能附加代码和堆栈跟踪:

public class Runner {

    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new TestModule());
        //next line throws the exception
        JMeterComponent jMeterComponent = 
             injector.getInstance(JMeterComponent.class);
        ....
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,我正在尝试实例化JMeterComponent类的对象.它的构造函数(稍后会看到)接受3个参数:所有这些参数都应该由IoC实例化并注入.

而这里的TestModule用的这些3个参数配置:

public class TestModule extends AbstractModule {

    @Override
    protected void configure() {
        bind(Callable.class).annotatedWith(Names.named("JMeter"))
                  .to(JMeterTask.class);      
        bind(Processor.class).annotatedWith(Names.named("JMeter"))
                  .to(JMeterResultsProcessor.class);
        bind(Renderer.class).annotatedWith(Names.named("JMeter"))
                  .to(JMeterResultsWikiRenderer.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,让我们来看看这些具体的实现- JMeterTask,JMeterResultsProcessorJMeterResultsWikiRenderer(所有的人都为简单起见假体):

public class JMeterTask implements Callable<JMeterRawResults> {

    public JMeterRawResults call() throws Exception {
        return new JMeterRawResults();
    }
}
Run Code Online (Sandbox Code Playgroud)

public class JMeterResultsProcessor implements 
                   Processor<JMeterRawResults, JMeterResults> {

    public JMeterResults process(JMeterRawResults raw) {
        return new JMeterResults();
    }
}
Run Code Online (Sandbox Code Playgroud)

public class JMeterResultsWikiRenderer implements Renderer<JMeterResults> {

    public Map<String, String> render(JMeterResults jMeterResults) {
        Map<String, String> results = Maps.newHashMap();
        ...
        return results;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在让我们来看看这个JMeterComponent类,这个实例的构造是整个DI相关内容的目标:

public class JMeterComponent extends AbstractComponent<String, String> {

    @Inject
    public JMeterComponent(@Named("JMeter") Callable<String> task, 
                           @Named("JMeter")Processor<String, String> processor, 
                           @Named("JMeter")Renderer<String> renderer) {
        super(task, processor, renderer);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是堆栈跟踪:

Exception in thread "main" com.google.inject.ConfigurationException: Guice configuration errors:

1) No implementation for stat.domain.Processor<java.lang.String, java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter) was bound.
  while locating stat.domain.Processor<java.lang.String, java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter)
    for parameter 1 at stat.components.jmeter.JMeterComponent.<init>(JMeterComponent.java:18)
  while locating cstat.components.jmeter.JMeterComponent

2) No implementation for stat.domain.Renderer<java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter) was bound.
  while locating stat.domain.Renderer<java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter)
    for parameter 2 at stat.components.jmeter.JMeterComponent.<init>(JMeterComponent.java:18)
  while locating stat.components.jmeter.JMeterComponent

3) No implementation for java.util.concurrent.Callable<java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter) was bound.
  while locating java.util.concurrent.Callable<java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter)
    for parameter 0 at stat.components.jmeter.JMeterComponent.<init>(JMeterComponent.java:18)
  while locating stat.components.jmeter.JMeterComponent
Run Code Online (Sandbox Code Playgroud)

一些额外的事实:

  1. 我用guice-2.0(带featured 标签)
  2. com.google.inject代码中的任何其他类中的包都没有任何注释
  3. 接口ProcessorRenderer放置在一个模块中,它们的jmeter实现(JMeterResultsProcessor和其他)和JMeterComponent类放在另一个模块中.

这就是关于它的几乎所有内容.

很抱歉这么长的帖子,感谢您的耐心阅读到最后.

关于为什么会出现错误以及如何解决错误的任何想法?

Col*_*inD 15

我在这里看到了几个问题.

首先,Callable并且Callable<String>是不同的.如果你想在Guice中注入一个Callable<String>(或者Processor<String, String>等等),你必须绑定一些东西Callable<String>,而不是Callable.

其次,你绑定CallableJMeterTask哪个实现,Callable<JMeterRawResults>但你注入Callable<String>JMeterComponent构造函数(同样的交易ProcessorRenderer).我会假设JMeterComponent应该Callable<JMeterRawResults>注入等.

无论如何,你需要做的是通用绑定使用TypeLiteral:

bind(new TypeLiteral<Callable<JMeterRawResults>>(){})
    .annotatedWith(Names.named("JMeter"))
    .to(JMeterTask.class);
Run Code Online (Sandbox Code Playgroud)