【问题标题】:Guice configuration error: No implementation was boundGuice 配置错误:没有绑定实现
【发布时间】:2010-12-27 16:45:16
【问题描述】:

我正在尝试使 DI 与 Guice 一起工作,完全按照 the manual 中的内容进行操作(在我看来)。

我无法解释这个问题,因为我并不真正理解它 - 一切似乎都很合乎逻辑并且应该可以工作......但它没有。所以,我只能附上代码和堆栈跟踪:

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);
        ....
    }
}

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

这里是TestModule,配置了这三个参数:

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);
    }
}

现在,让我们看看这些具体的实现 - JMeterTaskJMeterResultsProcessorJMeterResultsWikiRenderer(为了简单起见,它们都有假体):

public class JMeterTask implements Callable<JMeterRawResults> {

    public JMeterRawResults call() throws Exception {
        return new JMeterRawResults();
    }
}

public class JMeterResultsProcessor implements 
                   Processor<JMeterRawResults, JMeterResults> {

    public JMeterResults process(JMeterRawResults raw) {
        return new JMeterResults();
    }
}

public class JMeterResultsWikiRenderer implements Renderer<JMeterResults> {

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

现在让我们看看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);
    }
}

这是堆栈跟踪:

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

一些额外的事实:

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

这几乎就是所有要说的。

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

关于为什么会出现错误以及如何修复它的任何想法?

【问题讨论】:

    标签: java dependency-injection guice


    【解决方案1】:

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

    首先,CallableCallable&lt;String&gt; 是不同的。如果你想在 Guice 中注入一个Callable&lt;String&gt;(或Processor&lt;String, String&gt; 等),你必须绑定一些东西到Callable&lt;String&gt;,而不是Callable

    其次,您将Callable 绑定到实现Callable&lt;JMeterRawResults&gt;JMeterTask,但您在JMeterComponent 的构造函数中注入了Callable&lt;String&gt;ProcessorRenderer 的处理方式相同)。我将假设JMeterComponent 应该注入Callable&lt;JMeterRawResults&gt; 等。

    不管怎样,你需要做的是使用TypeLiteral通用绑定:

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

    【讨论】:

    • 是的,这行得通。不幸的是,它看起来不太好。无论如何,非常感谢。
    • 同意这看起来很难看。我通常在模块的实例变量中定义文字,因为它们在某种程度上是静态的。这使得绑定语句更好。
    • 我看不出有什么大不了的。一旦你习惯了 Guice 中的 TypeLiteral 成语,它在那里看起来非常自然。我说不要与 Guice 惯用的做事方式作斗争......但你喜欢什么。
    • 当你使用 Guice 时,模块是丑陋代码应该去的地方,所以你的业务逻辑中不需要丑陋的代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-05-23
    • 1970-01-01
    • 1970-01-01
    • 2011-12-15
    • 1970-01-01
    • 2021-07-25
    • 1970-01-01
    相关资源
    最近更新 更多