使用Gin / Guice注入实例

时间:2012-05-01 15:41:55

标签: gwt dependency-injection guice gin

我的GWT项目中通常有这种代码模式:

Menu errorMenu = new Menu(user, userController, -1);
Menu  searchMenu = new Menu(user, userController, 0);

errorView.setMenu(errorMenu);
searchView.setMenu(searchMenu);

如何使用Gin / Guice在Menu和其他“视图”中注入ErrorView个实例:

public ErrorView implements View {
 // Inject menu instance here
 private Menu menu;
}

这样,我不必手动创建和设置对象?

同样对于Menu类,如何注入“user”和“userController”对象,这样我每次实例化时都不必在每个Menu实例上传递它。

1 个答案:

答案 0 :(得分:10)

借助本教程http://code.google.com/p/google-gin/wiki/GinTutorial,您的问题看起来并不那么困难。要将菜单实例注入View,应该运行几个步骤。

  1. 将@Inject注释添加到菜单字段。

    public ErrorView implements View {
    
      @Inject
      private Menu menu;
    }
    
    public SearchView implements View {
    
      @Inject
      private Menu menu;
    }
    

    但是在这种情况下,在View对象初始化期间(在构造函数中)菜单字段将为null。因此,我更喜欢将此字段添加到构造函数参数中。

    public ErrorView implements View {
    
      private final Menu menu;
    
      @Inject
      public ErrorView(Menu menu) {
        this.menu = menu;
      }
    }
    
    public SearchView implements View {
    
      private final Menu menu;
    
      @Inject
      public SearchView(Menu menu) {
        this.menu = menu;
      }
    }
    

    当然,如果你在ErrorView的构造函数中有许多其他参数,它将无法工作,因为所有这些参数都需要注入。

  2. 现在我们必须确保GIN知道ErrorView中的菜单字段应该是 注入new Menu(user, userController, -1)和另一个注入 SearchView至 - new Menu(user, userController, 0)。我们做得到 通过以下几种方式:

    • 在您的菜单字段中添加注释@Named("searchMenu")@Named("errorMenu")

      public ErrorView implements View {
      
        @Inject
        @Named("errorMenu")
        private Menu menu;
      }
      

      public ErrorView implements View {
      
        private final Menu menu;
      
        @Inject
        public ErrorView(@Named("errorMenu") Menu menu) {
          this.menu = menu;
        }
      } 
      

      在您的GIN模块中,您应该提供此注释的定义。

          public class ApplicationGinModule extends AbstractGinModule {
      
            protected void configure() {
              bind(Menu.class).annotatedWith(Names.named("errorMenu")).to(DefaultErrorMenu.class);
              bind(Menu.class).annotatedWith(Names.named("searchMenu")).to(DefaultSearchMenu.class);
      
              //assume that User and UserController classes have default constructors  
              //otherwise you should provide correct injection depending on your business-logic
              bind(User.class).in(Singleton.class); 
              bind(UserController.class).in(Singleton.class);  
            }
          }
      
          public class DefaultErrorMenu extends Menu {
      
            @Inject
            public DefaultErrorMenu(User user, UserController userController) {
              super(user, userController, -1);
            }
          }
      
          public class DefaultSearchMenu extends Menu {
      
            @Inject
            public DefaultSearchMenu(User user, UserController userController) {
              super(user, userController, 0);
            }
          }
      
    • 在菜单字段中创建自己的注释@SearchMenu@ErrorMenu,并在模块中定义它们。

      注释示例:

      @Retention(RetentionPolicy.RUNTIME)
      @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, ElementType.TYPE})
      @BindingAnnotation
      public @interface ErrorMenu {
      }
      

      用法:

      public ErrorView implements View {
      
        @Inject
        @ErrorMenu
        private Menu menu;
      }
      

      public ErrorView implements View {
      
        private final Menu menu;
      
        @Inject
        public ErrorView(@ErrorMenu Menu menu) {
          this.menu = menu;
        }
      } 
      

      然后按照你如何定义@Named(“ErrorMenu”)的方式定义注释:

      bind(Menu.class).annotatedWith(ErrorMenu.class).to(DefaultErrorMenu.class);
      
  3. 在某些示例中,我将菜单字段设为final并删除setter,但如果您确实需要菜单的可变状态,则可以保持不变。