【问题标题】:Guice configure scopeGuice 配置范围
【发布时间】:2016-08-10 18:59:45
【问题描述】:

我是 Guice 的新手,并试图了解您的 Module 类中 configure() 方法的范围。目前以下是我的应用程序结构。有用。

class MainClass {
     public static void main(String[] args) {
         Injector injector = createInjector(new MainModule(param1, param2, param3));
         injector = injector.createChildInjector(injector.getInstance(FuncModule.class));

     }
}

FuncModule.java

 class FuncModule extends AbstractModule {

   @Override
   public void configure() {

         // Register a AWS SWF Workflow Worker
         // Register a AWS SWF Activity Worker

         // Instantiate WorkflowFactory class
         TempWorkflowClientExternalFactory obj = new TempWorkflowClientExternalFactoryImpl(<param1>, <param2>);
         bind(TempWorkflowClientExternalFactory.class).annotatedWith(Names.named("temp1")).toInstance(obj); 
   }
 }

我试图了解我的配置方法是否“做得太多”。配置方法的意图/范围是否仅限于绑定?如果是这样,哪里是注册工人和实例化工厂对象的最佳位置?

【问题讨论】:

    标签: java binding guice


    【解决方案1】:

    您想知道您的configure 方法是否适合这种类型的初始化是正确的;这是一个判断的问题。 Guice 确实有这样的说法:Modules should be fast and side-effect free.

    但是,Java 语言的全部功能是有代价的:在一个模块中做太多事情很容易。连接到数据库连接或在 Guice 模块中启动 HTTP 服务器是很诱人的。不要这样做!在模块中进行繁重的工作会带来问题:

    • 模块会启动,但不会关闭。如果您在模块中打开数据库连接,您将没有任何挂钩可以关闭它。
    • 模块应该被测试。如果一个模块打开一个数据库作为一个执行过程,就很难为它编写单元测试。
    • 模块可以被覆盖。 Guice 模块支持覆盖,允许生产服务替换为轻量级或测试服务。当生产服务作为模块执行的一部分创建时,此类覆盖无效。

    需要考虑的其他一些因素:

    1. 您的 Guice 模块仍然是一个 Java 类,并且可以并且应该像任何其他类一样遵守Single Responsibility Principle。如果您的依赖项的构造或配置超过一两个屏幕,或者很难用一两句话描述,那么可能是时候分解模块(参见install)或将构造/配置提取到它的自己的方法或类。您在configure 的评论部分给了我们一个提示:也许是时候提取方法或类,这样代码就更具有自我描述性了。

    2. Guice 只是一种依赖注入框架,它的设计目的是只需要很少的 Guice 特定代码或模式。使用 JSR330 兼容的注解 (@Inject) 和接口 (Provider),您应该能够手动复制或替换 Guice 的功能——或者使用不同的框架,如 SpringDagger (2)——没有太多麻烦。然而,Java 模块实例是 Guice 独有的;如果您想在非 Guice 上下文中使用模块中的自定义初始化代码,则需要对其进行重构或重写。这可能是首先将可重用初始化代码与 Guice 模块分开的一个很好的理由。

    3. 按照类似的思路,正如 Guice wiki 所提到的,您应该在类中测试任何重要的逻辑。没有 Guice,Guice 模块和它们的 configure 方法很难测试;如果外部构造/配置位于单独的类或方法中,您可能会发现它更容易测试。

    4. 当您调用 createInjectorcreateChildInjector 时,您在模块的 configure 方法中执行的任何初始化操作都会发生,以及以未指定顺序的所有其他模块。这为您提供了非常小的粒度来设置日志记录、推迟到后台线程、优雅地catch 异常,或者以其他方式控制初始化发生的时间和方式。通过将第三方初始化程序代码提取到单独的类或方法,或者 Provider 或 @Provides 方法,您可以更灵活地决定何时以及如何运行。

    5. 话虽如此,Guice 确实允许实例绑定,并且在模块中看到简单且轻量级的构造函数调用、初始化程序调用和其他实例准备代码是很常见的。为几行微不足道的初始化创建一个全新的类可能是矫枉过正。

    简而言之,保留简单/简短/安全的初始化调用,但一旦事情变得复杂/冗长/危险,请准备好提取创建或初始化以给予自己更多控制权。


    附:另外,虽然从 Injector 获取 Module 实例并没有技术上的错误,但请注意,这不是一种常见的模式。充其量,这违反了您在模块configure 时无法访问正常工作的注射器的经验法则;在最坏的情况下,您可能会发现很难推断您实际调用的是哪个 Injector,以及您可以使用哪些绑定。您可以保留它,但要谨慎使用,并考虑通过将父注入器来源的依赖项作为模块构造函数参数传递来保持明确。

    /** Injected child module. Get this from a parent injector. */
    public class BModule extends AbstractModule {
      @Inject Injector injector;  // You can always inject the Injector...
    
      @Override public void configure() {
        bind(B.class).to(BImpl.class);
      }
    
      @Provides C provideC(B b) {
        return new C(b);
      }
    
      @Provides D provideD() {
        return new D(injector.getInstance(B.class));  // but this won't work;
                                                      // injector is the parent,
                                                      // not the one with this module.
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-10-07
      • 1970-01-01
      • 1970-01-01
      • 2015-07-16
      • 2011-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多