2013-04-26 102 views
4

我想在不引入注释或使用字符串键名称的情况下完成以下操作,是否可以使用Guice?此外,为MyService及其ExecutorService绑定引入第三个私有模块并不理想,因为我希望ExecutorService是整个应用程序的单例,不仅注入MyService,还注入其他类,例如MyOtherServiceGuice子模块阻止继承绑定

public class Main { 
    public static void main(String[] args) { 
    final Injector injector = Guice.createInjector(new MyAppModule()); 
    final MyService service = injector.getInstance(MyService.class); 
    service.printInternals(); 
    // Ideally this would print something like: 
    // My Executor: [email protected] 
    // Red Executor: [email protected] 
    // Blue Executor: [email protected] 
    } 
} 

public class MyAppModule extends PrivateModule { 
    @Override 
    protected void configure() { 
    install(new RedModule()); 
    install(new BlueModule()); 
    bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor()); 
    bind(MyService.class).to(MyServiceImpl.class); 
    expose(MyService.class); 
    } 
} 

public class BlueModule extends PrivateModule { 
    @Override 
    protected void configure() { 
    bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor()); 
    bind(BlueService.class).to(BlueServiceImpl.class); 
    expose(BlueService.class); 
    } 
} 

public interface BlueService { 
    void printInternals(); 
} 

class BlueServiceImpl implements BlueService { 
    private final ExecutorService executor; 

    @Inject 
    BlueServiceImpl(final ExecutorService executor) { 
    this.executor = executor; 
    } 

    @Override 
    public void printInternals() { 
    System.out.println("Blue Executor: " + executor); 
    } 
} 

RedModule, RedService and RedServiceImpl所有镜像它们各自Blue*类。

最后MyService,它使用RedBlue Services以及它自己的ExecutorService

class MyServiceImpl implements MyService { 
    private final ExecutorService executor; 
    private final RedService red; 
    private final BlueService blue; 

    @Inject 
    MyServiceImpl(final ExecutorService executor, final RedService red, final BlueService blue) { 
    this.executor = executor; 
    this.red = red; 
    this.blue = blue; 
    } 

    @Override 
    public void printInternals() { 
    System.out.println("My Executor: " + executor); 
    red.printInternals(); 
    blue.printInternals(); 
    } 
} 

回答

6

TL; DR:隔离BlueRed模块自身的喷油器和您的App's模块,该模块调用创建提供商注入器的getInstance()方法来检索您的应用程序所需的服务。

现在对于我是怎么来到了解决方案:

私人模块可以让你的大部分的方式出现,见my experimentation

但是......

比方说,我正在开发一种使用服务做一些完全真棒的应用程序。

public class MyAppModule extends PrivateModule { 
    bind(AwesomeService.class).to(AwesomeServiceImpl.class); 
    expose(AwesomeService.class); 
} 

现在我AwesomeService的具体实施需要的几件事情是因为真棒,因为它是:

class AwesomeServiceImpl implements AwesomeService { 
    @Inject 
    AwesomeServiceImpl(BlueService blue, RedService red, ExecutorService executor) { ... } 
} 

它碰巧的是,一些正直互联网常客创造与吉斯模块独立罐子提供RedBlue服务。因此,我将罐子添加到我的类路径和修改MyAppModule让我AwesomeService可以使用第三方RedBlue服务:

public class MyAppModule extends PrivateModule { 
    install(new RedModule()); 
    install(new BlueModule()); 
    bind(AwesomeService.class).to(AwesomeServiceImpl.class); 
    expose(AwesomeService.class); 
} 

我还需要为我的AwesomeServiceExecutorService,所以我会继续前进,绑定到一个明确的实例现在:

public class MyAppModule extends PrivateModule { 
    install(new RedModule()); 
    install(new BlueModule()); 
    bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor()); 
    bind(AwesomeService.class).to(AwesomeServiceImpl.class); 
    expose(AwesomeService.class); 
} 

啊,但该死的,显然我的互联网朋友决定揭露不仅RedServiceBlueService绑定我的AwesomeService的需要,也是一个ExecutorService我不想:

public final class BlueModule extends PrivateModule { 
    bind(ExecutorService.class).toInstance(Executors.newCachedThreadPool()); 
    bind(BlueService.class).to(BlueServiceImpl.class); 

    expose(ExecutorService.class); 
    expose(BlueService.class); 
} 

public final class RedModule extends PrivateModule { 
    bind(ExecutorService.class).toInstance(Executors.newCachedThreadPool()); 
    bind(RedService.class).to(RedServiceImpl.class); 

    expose(ExecutorService.class); 
    expose(RedService.class); 
} 

没问题,我就换了模块的私人模块以及只露出我关心的服务:

public class MyAppModule extends PrivateModule { 
    install(new PrivateModule() { 
    install(new RedModule()); 
    expose(RedService.class); 
    }); 
    install(new PrivateModule() { 
    install(new BlueModule()); 
    expose(BlueService.class); 
    }); 
    bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor()); 
    bind(AwesomeService.class).to(AwesomeServiceImpl.class); 
    expose(AwesomeService.class); 
} 

啊,但该死再次,我的ExecutorService绑定由我的私有包装模块继承,并与RedModuleBlueModule中定义的内部绑定冲突。我想我可以在我的AwesomeService构造函数中注释或命名我的ExecutorService,但是如果我希望ExecutorService成为在我的应用中由20,30或40种不同服务共享的单身人士,我该怎么办?我必须用这个注释来污染我所有的ExecutorService注射剂。

或者我想我可以做一些挂羊头卖狗肉,错开绑定和隐藏ExecutorService所以它并不冲突的ExecutorServiceRedModuleBlueModule创造,但这似乎只是错误:

public class MyAppModule extends PrivateModule { 
    install(new PrivateModule() { 
    install(new RedModule()); 
    expose(RedService.class); 
    }); 
    install(new PrivateModule() { 
    install(new BlueModule()); 
    expose(BlueService.class); 
    }); 

    final Module myAppExecutorService = new PrivateModule() { 
    bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor()); 
    expose(ExecutorService.class); 
    }; 
    install(new PrivateModule() { 
    install(myAppExecutorService); 
    bind(AwesomeService.class).to(AwesomeServiceImpl.class); 
    expose(AwesomeService.class); 
    }); 
    expose(AwesomeService.class); 
} 

必须有做一个更好的方法...并且有...注射器!

public class MyAppModule extends PrivateModule { 
    private static final Injector blueInjector = Guice.createInjector(new BlueModule()); 
    private static final Injector redInjector = Guice.createInjector(new RedModule()); 

    @Override 
    protected void configure() 
    { 
    bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor()); 
    bind(MyService.class).to(MyServiceImpl.class); 
    bind(MyOtherService.class).to(MyOtherServiceImpl.class); 
    expose(MyService.class); 
    expose(MyOtherService.class); 
    } 

    @Provides 
    RedService getRedService() 
    { 
    return redInjector.getInstance(RedService.class); 
    } 

    @Provides 
    BlueService getBlueService() 
    { 
    return blueInjector.getInstance(BlueService.class); 
    } 
} 

现在绑定,并在BlueModuleRedModule都暴露不会污染我AwesomeService'sExecutorService,但我仍然可以得到我的手对这些多汁BlueServiceRedService类我这么拼命想ExecutorService

希望这会在未来节省一些时间!

+0

请注意,使用注入器而不是模块将会阻止您重写它们。 https://github.com/google/guice/issues/347 – Alex 2015-05-22 11:12:12