【问题标题】:Guice Constructor Injection withOUT Annotations?没有注释的Guice构造函数注入?
【发布时间】:2018-06-13 21:40:29
【问题描述】:

有人可以帮助实现没有注释的 Guice 吗?

public interface IAnimal {
  void makeNoise();
}


public interface IVehicle {
  int getWheelCount();
}





import org.apache.commons.logging.Log;
public class Car implements IVehicle {

    private Log Logger;

    public Car(Log lgr) {
        this.Logger = lgr;
    }

    public final int getWheelCount() {
      this.Logger.info("getWheelCount is returning 4");
      return 4;
    }
}




import org.apache.commons.logging.Log;
public class Dog implements IAnimal {

    private Log Logger;

    public Dog(Log lgr) {
        this.Logger = lgr;
    }

    public final void makeNoise() {
        this.Logger.info("Bark Bark Bark");
    }
}

pom.xml

    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.1.3</version>
    </dependency>

    <dependency>
        <groupId>com.google.inject</groupId>
        <artifactId>guice</artifactId>
        <version>4.2.0</version>
    </dependency>

我尝试过的:

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.google.inject.*;

public class App {

  public static void main(String[] args) {


    Log localLogger = 
        LogFactory.getLog(App.class);

    Injector injector = Guice.createInjector();

    IVehicle veh = injector.getInstance(Car.class);  
    int wc = veh.getWheelCount();

    IAnimal amh = injector.getInstance(Dog.class);  
    amh.makeNoise();
  }
}

我得到的错误是:

Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.

我理解错误。

但我希望我可以将 Guice“指向”正确的构造函数……而不是使用注释。

如您所见,使用默认/空构造函数不是一个好选择,因为这个示例很简单,但我想坚持使用基于构造函数的注入。

追加:

根据我在 cmets 中从 Hemant Singh 那里得到的“提示”,我想我已经接近了。

我创建了一个 ProductionInjectModule,它使用

bind(MyInterface.class).toConstructor(MyConcrete.class.getConstructor(org.apache.commons.logging.Log.class));

但即使我通过指向特定的构造函数(使用“toConstructor”)来“强迫”问题......我仍然得到:

类必须有一个(并且只有一个)带有注释的构造函数 @Inject 或非私有的零参数构造函数。

呸呸呸呸呸!

完整的“模块”代码如下:

public class App {

  public static void main(String[] args) {
    runGuice();

  }

  private static void runGuice() {
    Log localLogger = LogFactory.getLog(App.class);

    ProductionInjectModule pm = new ProductionInjectModule(localLogger);
    Injector injector = Guice.createInjector(pm);
    ////Injector injector = Guice.createInjector();
    //// injector.injectMembers(localLogger);

    IVehicle veh = injector.getInstance(Car.class);
    int wc = veh.getWheelCount();

    IAnimal amh = injector.getInstance(Dog.class);
    amh.makeNoise();
  }

 }




import com.google.inject.AbstractModule;
import com.google.inject.Module;

public class ProductionInjectModule extends AbstractModule implements Module {
  // public void configure(Binder binder) {
  // binder.bind(IVehicle.class).to(Car.class);
  //// binder.bind(InterfaceB.class).to(ConcreteB.class);
  //// binder.bind(InterfaceC.class).to(ConcreteC.class);
  // }

  private final org.apache.commons.logging.Log Logger;

  public ProductionInjectModule(org.apache.commons.logging.Log concreteLogger) {
    this.Logger = concreteLogger;
  }

  @Override
  protected void configure() {
    try {
      bind(org.apache.commons.logging.Log.class).toInstance(this.Logger);
      bind(IVehicle.class).toConstructor(Car.class.getConstructor(org.apache.commons.logging.Log.class));
      bind(IAnimal.class).toConstructor(Dog.class.getConstructor(org.apache.commons.logging.Log.class));
    } catch (NoSuchMethodException e) {
      addError(e);
    }
  }

}

按照同样的提示,我找到了一些支持文档:

来自:http://www.baeldung.com/guice

你也可以注入一个没有默认 no-arg 的依赖 使用构造函数绑定的构造函数:

>     public class BasicModule extends AbstractModule {
>   
>     @Override
>     protected void configure() {
>         bind(Boolean.class).toInstance(true);
>         bind(Communication.class).toConstructor(
>           Communication.class.getConstructor(Boolean.TYPE)); } 
The snippet above will inject an instance of Communication using the

采用布尔参数的构造函数。我们提供真实的论据 通过定义布尔值的非目标绑定到构造函数 类。

这个非目标绑定将被急切地提供给任何构造函数 接受布尔参数的绑定。采用这种方法,所有 通信的依赖被注入。

构造函数特定绑定的另一种方法是实例 绑定,我们直接在绑定中提供一个实例:

>     public class BasicModule extends AbstractModule {
>   
>     @Override
>     protected void configure() {
>         bind(Communication.class)
>           .toInstance(new Communication(true));
>     }     }

2019 年夏季附加赛:

使用“slf4j”而不是“org.apache.commons”会更明智

org.slf4j.Logger 
and
org.slf4j.LoggerFactory.getLogger(MyClass.class);

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.25</version>
</dependency>

为什么?

https://www.slf4j.org/codes.html#multiple_bindings

库或框架等嵌入式组件不应声明 对任何 SLF4J 绑定的依赖,但仅依赖于 slf4j-api。当一个 library 声明了对 SLF4J 绑定的编译时依赖,它 将这种绑定强加给最终用户,从而否定了 SLF4J 的目的。 当您遇到声明编译时的嵌入式组件时 依赖于任何 SLF4J 绑定,请花时间联系 所述组件/库的作者,并请他们修改他们的 方式。

【问题讨论】:

  • 我想你可以用github.com/google/guice/wiki/ToConstructorBindings解决这个问题
  • @HemantSingh 你让我更接近了。谢谢你。我附上了我的答案。即使我说“使用这个构造函数”,它仍然让我很难过。它〜应该工作。
  • 我明白了!谢谢@HemantSingh
  • 谁反对这个?有什么理由吗? #downvotingNeedsAccountability
  • 不是我,顺便说一句,我现在投了赞成票。

标签: java dependency-injection guice


【解决方案1】:

我明白了!我在原始问题中的“追加:”区域很接近!但现在我看到了我的小错误。

我上面的 ProductionInjectModule 是正确的。

我的“要求解决”是错误的。

请注意,在我的 getInstance 中,我还有混凝土。

我需要这个:(强调 getInstance 的参数)

IVehicle veh = injector.getInstance(IVehicle.class);
int wc = veh.getWheelCount();

IAnimal amh = injector.getInstance(IAnimal.class);
amh.makeNoise();

完整的工作代码:(使用上面的接口和具体)

public class App {

  public static void main(String[] args) {
    runGuice();

  }

  private static void runGuice() {
    Log localLogger = LogFactory.getLog(App.class);

    ProductionInjectModule pm = new ProductionInjectModule(localLogger);
    Injector injector = Guice.createInjector(pm);

    IVehicle veh = injector.getInstance(IVehicle.class);
    int wc = veh.getWheelCount();

    IAnimal amh = injector.getInstance(IAnimal.class);
    amh.makeNoise();
  }

 }




import com.google.inject.AbstractModule;
import com.google.inject.Module;

public class ProductionInjectModule extends AbstractModule implements Module {

  private final org.apache.commons.logging.Log Logger;

  public ProductionInjectModule(org.apache.commons.logging.Log concreteLogger) {
    this.Logger = concreteLogger;
  }

  @Override
  protected void configure() {
    try {
      bind(org.apache.commons.logging.Log.class).toInstance(this.Logger);
      bind(IVehicle.class).toConstructor(Car.class.getConstructor(org.apache.commons.logging.Log.class));
      bind(IAnimal.class).toConstructor(Dog.class.getConstructor(org.apache.commons.logging.Log.class));
    } catch (NoSuchMethodException e) {
      addError(e);
    }
  }

}

2019 年夏季附加赛:

使用“slf4j”而不是“org.apache.commons”会更明智

org.slf4j.Logger 
and
org.slf4j.LoggerFactory.getLogger(MyClass.class);

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.25</version>
</dependency>

当然,请检查最新更新:

https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.slf4j%22%20AND%20a%3A%22slf4j-api%22

为什么?

https://www.slf4j.org/codes.html#multiple_bindings

库或框架等嵌入式组件不应声明 对任何 SLF4J 绑定的依赖,但仅依赖于 slf4j-api。当一个 library 声明了对 SLF4J 绑定的编译时依赖,它 将这种绑定强加给最终用户,从而否定了 SLF4J 的目的。 当您遇到声明编译时的嵌入式组件时 依赖于任何 SLF4J 绑定,请花时间联系 所述组件/库的作者,并请他们修改他们的 方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-13
    • 2017-04-26
    • 2017-07-14
    • 2019-10-16
    • 1970-01-01
    相关资源
    最近更新 更多