Guice:注射与接线

时间:2013-02-02 13:38:55

标签: java dependency-injection guice

很多时候,类需要被实例化(构造),然后在它们被使用之前“连线”(配置)。例如:

// Construction.
EventBus bus = new EventBus();
FizzEventHandler fizzHandler = new FizzHandler();
BuzzEventHandler buzzHandler = new BuzzHandler();

// Wiring.
bus.register(fizzHandler);
bus.register(buzzHandler);

在Guice中,我们使用Binder

完成第一部分(构造;注入)
public class MyModule extends AbstractModule {
    @Override
    public void configure() {
        bind(EventBus.class).to(SimpleEventBus.class);
        bind(FizzEventHandler.class).to(DefaultFizzEventHandler.class);
        bind(BuzzEventHandler.class).to(DefaultBuzzEventHandler.class);
    }
}

布线在哪里发生?当我的基于Guice的应用程序启动时,我们参与DI“引导”过程:

public class MyApp {
    private EventBus bus;
    private FizzEventHandler fizzHandler;
    // ...etc.

    public static void main(String[] args) {
        MyApp app = new MyApp();
        app.run();
    }

    public MyApp() {
        // Bootstrap DI.
        MyModule myModule = new MyModule();
        Injector injector = Guice.createInjector(myModule);

        bus = injector.inject(EventBus.class);
        fizzHandler = injector.inject(FizzEventHandler.class);
        // ...etc.

        // Wire
        bus.register(fizzHandler);
    }
}

这适用于顶级(根)DI类。但随着我们进一步“关闭”依赖树,并进入应用程序使用的所有其他对象,将布线逻辑放在这样的构造函数中是丑陋的(我相信)是一种沮丧的做法

所以我问:哪个战斗疲惫的Guice老兵放置他们的布线/配置代码?

3 个答案:

答案 0 :(得分:3)

我在一个使用Guice的相当大的系统(~3000个类)上工作。我会说我们的方法是用构造函数做所有事情。你所描述的并没有明显的“建筑”和“布线”活动,只有建筑。

在您的示例中,事件处理程序将是总线的构造函数参数,它将在构造函数中注册它们。

如果您希望相当灵活地注入给定类型的所有组件(这里,您希望将所有事件侦听器注入总线),则可以使用multibindings。但是,我不认为我们在代码库中实际使用它;我们只写出需要注入的所有东西的手册,这在实践中并不是那么艰难。

答案 1 :(得分:2)

我通常使用多个模块,由逻辑功能分隔。因此,一个模块可能在其中具有身份验证,另一个模块具有数据存储库,另一个模块正在使用,。这允许您使用不同的模块进行模拟,缓存Vs.非缓存,或只是同一服务的不同实现,并快速轻松地切换出依赖关系块。

为了使事情更加灵活,您可以拥有一个配置文件,该文件声明了注入器启动时应该使用的模块。

答案 2 :(得分:0)

当我在实例化对象后立即执行某些逻辑时,我通常在使用@Provides注释的方法中执行此操作。您的示例可能如下所示:

public class MyModule extends AbstractModule {
   @Override
   protected void configure() {

    bind(FizzEventHandler.class).to(DefaultFizzEventHandler.class);
    bind(BuzzEventHandler.class).to(DefaultBuzzEventHandler.class);

   }


   @Provides
   public EventBus getEventBus(SimpleEventBuss simpleBus/* this here is going to be injected as it is a class not an interface and Guice is clever and it know how to do it ;) */
     , FizzEventHandler fizz, BuzzEventHandler buzz) {
    simpleBus.register(fizz);
    simpleBus.register(buzz);
    return simpleBus;
   }
  }