论坛首页 Java版

Guice目前来说还只是个玩具

浏览 9259 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
最后更新时间:2008-03-22
ajoo 写道
我不知道为什么guice不能用在“企业”应用上。我们组大家对抛弃spring都欢欣鼓舞地。

guice的问题嘛,自然有。不过你要是没用过的话,也不容易讲明白。而且,等2.0出来,很多问题可能就解决了。


能在这儿跟贴的,估计guice的sample多多少少都跑过,加上guice语法也很简单,所以估计算得上“入门”的水平还是比较容易达到的。我的思路是,让热爱guice的人(比如 ajoo)谈谈guice的缺点,是不是比不喜欢guice的说的更有价值些?不用担心大家看不懂,我想guice还没复杂到“深奥”的程度。
   
0 请登录后投票
最后更新时间:2008-03-22
好吧,我说说1.0的一些不足吧(其实你这些要求并不合理,你试试让rod等人告诉你spring的缺陷?只怕人家马上就defensive起来)。

1。provider使用匿名类,语法相当烦琐。比如你要从spring移植出来,那些<bean>就会变成一堆provider,看起来并不清爽——虽然比xml清爽一点。为了解决这个问题,我实现了一个2.0将要出来的功能:provider method。比如,对这么一个provider:
bind(Foo.class).toProvider(new Provider<Foo>() {
  @Inject Provider<Bar> barProvider;
  @Inject Provider<Baz> bazProvider;
  public Foo get() {
    FooImpl impl = new FooImpl();
    impl.setBar(barProvider.get());
    impl.setBaz(bazProvider.get());
    return impl;
  }
});

改写成provider method语法就是:
@Provide
public Foo foo(Bar bar, Baz baz) {
    FooImpl impl = new FooImpl();
    impl.setBar(bar);
    impl.setBaz(baz);
    return impl;
}

这下清爽了。我们这个扩展不会开源(没什么意义),等2.0吧。

2。provider注入有个bug。如果容器找不到Bar,它不会抛异常,而是打印一个stack trace了事。2.0会解决这个问题的。

3。provider无法得知自己被绑定的key。比如,你想在系统里面注入Bigtable。每个Bigtable都有一个名字,这个名字我们希望可以通过property来注入:
@Provide @ForFoo
public Bigtable fooBigtable(@Named("fooTable") String tableName) {
  return BtUtil.createTable(tableName);
}

单独一个bigtable没问题。但是如果你系统里有七八个bigtable,那就要写七八个binding。很麻烦。理想情况是可以让provider知道自己被绑定在@Named("fooTable")上了,这样它可以直接向容器要求那个"fooTable"的property的值。结果就是你只需要一个provider:
bind(Bigtable.class).annotatedWith(Named.class).toProvider(new SuperProvider<Bigtable>() {
  @Inject Injector injector;
  public Bigtable get(Key<? super Bigtable> key) {
    Key<String> tableNameKey = Key.get(String.class, Names.getName(key.getAnnotation());
    String tableName = injector.getInstance(tableNameKey);
    return BtUtil.createTable(tableName);
  }
});

然后你就可以到处用"@Named("fooTable") Bigtable bigtable"来注入了。这个问题期望在2.0里能得到解决。

4。所谓的robot leg问题。就是说,Guice最擅长的是创建一个静态对象网络,也就是说,每个Key在任何时候任何上下文都只对应一个实现。但是有时候不是那么简单。

比如,我的系统是个分层的结构。A依赖B,B依赖C,C依赖D。好,Guice老老实实地把对象网络建立好了。现在,我要出妖蛾子了,我的D要根据当前request的客户browser类型来变化,比如对IE,我用IE_D,对FF用FF_D。好了,现在麻烦了,我要弄一个@ForIe和一个@ForFf的annotation,这倒也没什么,但是我现在要把C也分裂成@ForIe的C和@ForFf的C,还要分裂B,还有A。这样我就可以在最外层的action里面这么写:
class MyAction {
  private final A forIe;
  private final A forFf;

  @Inject public MyAction(@ForIe A forIe, @ForFf A forFf) {
    ...
  }

  public void run() {
    if (isIe()) {
      forIe.run();
    } else {
      forFf.run();
    }
  }
}


但是module的复杂度一下子提升上去了。

对这个问题目前七嘴八舌有很多解决方法的提议。我喜欢Brian Slensinskey的提议,就是说,允许Injector在动态改变binding。然后在Guice核心支持所谓客户自定义工厂的概念。这样不但能解决robot leg问题,还可以解决Provider的侵入性问题。我们可以自己定义自己的Factory, Getter,而不是有时候被邪恶诱惑使用容器提供的Provider接口。

5。Guice不支持组合不同的binding annotation。比如,我如果有两把铁锹,一个是用来铲雪的,一个用来挖地的,好办,我可以写两个annotation,@ForSnowShovelling, @ForDigging。但是如果回头我发现有另外一个维度,比如便宜的和贵的,我即使可以弄两个@Expensive, @Cheap,我也没办法用组合@Cheap @ForSnowShovelling来表达“便宜的雪铲”这个概念。我只能写@CheapForSnowShovelling。:-(

6。你可以注射List<String>, List<Integer>, List<Map<String, Iterable<Object>>>,都行,但是,不能注射List<T>,不能注射List<? extends Closeable>。也就是说,不支持wildcard,并且类型参数必须是具体的,而不是T。

7。Guice的fluent interface api用起来还成。但是mock测试起来(写扩展的时候,不是应用)比较麻烦,看javadoc也比较复杂,要看那一堆名字好长好长的中间Builder对象的文档。

8。没有lifecycle,至少destroy或者PreDestroy还是有用的。


大致就想到这么多。
   
0 请登录后投票
最后更新时间:2008-03-23
ajoo 写道
好吧,我说说1.0的一些不足吧(其实你这些要求并不合理,你试试让rod等人告诉你spring的缺陷?只怕人家马上就defensive起来)。

1。provider使用匿名类,语法相当烦琐。比如你要从spring移植出来,那些<bean>就会变成一堆provider,看起来并不清爽——虽然比xml清爽一点。为了解决这个问题,我实现了一个2.0将要出来的功能:provider method。比如,对这么一个provider:
bind(Foo.class).toProvider(new Provider<Foo>() {
  @Inject Provider<Bar> barProvider;
  @Inject Provider<Baz> bazProvider;
  public Foo get() {
    FooImpl impl = new FooImpl();
    impl.setBar(barProvider.get());
    impl.setBaz(bazProvider.get());
    return impl;
  }
});

改写成provider method语法就是:
@Provide
public Foo foo(Bar bar, Baz baz) {
    FooImpl impl = new FooImpl();
    impl.setBar(bar);
    impl.setBaz(baz);
    return impl;
}

这下清爽了。我们这个扩展不会开源(没什么意义),等2.0吧。

2。provider注入有个bug。如果容器找不到Bar,它不会抛异常,而是打印一个stack trace了事。2.0会解决这个问题的。

3。provider无法得知自己被绑定的key。比如,你想在系统里面注入Bigtable。每个Bigtable都有一个名字,这个名字我们希望可以通过property来注入:
@Provide @ForFoo
public Bigtable fooBigtable(@Named("fooTable") String tableName) {
  return BtUtil.createTable(tableName);
}

单独一个bigtable没问题。但是如果你系统里有七八个bigtable,那就要写七八个binding。很麻烦。理想情况是可以让provider知道自己被绑定在@Named("fooTable")上了,这样它可以直接向容器要求那个"fooTable"的property的值。结果就是你只需要一个provider:
bind(Bigtable.class).annotatedWith(Named.class).toProvider(new SuperProvider<Bigtable>() {
  @Inject Injector injector;
  public Bigtable get(Key<? super Bigtable> key) {
    Key<String> tableNameKey = Key.get(String.class, Names.getName(key.getAnnotation());
    String tableName = injector.getInstance(tableNameKey);
    return BtUtil.createTable(tableName);
  }
});

然后你就可以到处用"@Named("fooTable") Bigtable bigtable"来注入了。这个问题期望在2.0里能得到解决。

4。所谓的robot leg问题。就是说,Guice最擅长的是创建一个静态对象网络,也就是说,每个Key在任何时候任何上下文都只对应一个实现。但是有时候不是那么简单。

比如,我的系统是个分层的结构。A依赖B,B依赖C,C依赖D。好,Guice老老实实地把对象网络建立好了。现在,我要出妖蛾子了,我的D要根据当前request的客户browser类型来变化,比如对IE,我用IE_D,对FF用FF_D。好了,现在麻烦了,我要弄一个@ForIe和一个@ForFf的annotation,这倒也没什么,但是我现在要把C也分裂成@ForIe的C和@ForFf的C,还要分裂B,还有A。这样我就可以在最外层的action里面这么写:
class MyAction {
  private final A forIe;
  private final A forFf;

  @Inject public MyAction(@ForIe A forIe, @ForFf A forFf) {
    ...
  }

  public void run() {
    if (isIe()) {
      forIe.run();
    } else {
      forFf.run();
    }
  }
}


但是module的复杂度一下子提升上去了。

对这个问题目前七嘴八舌有很多解决方法的提议。我喜欢Brian Slensinskey的提议,就是说,允许Injector在动态改变binding。然后在Guice核心支持所谓客户自定义工厂的概念。这样不但能解决robot leg问题,还可以解决Provider的侵入性问题。我们可以自己定义自己的Factory, Getter,而不是有时候被邪恶诱惑使用容器提供的Provider接口。

5。Guice不支持组合不同的binding annotation。比如,我如果有两把铁锹,一个是用来铲雪的,一个用来挖地的,好办,我可以写两个annotation,@ForSnowShovelling, @ForDigging。但是如果回头我发现有另外一个维度,比如便宜的和贵的,我即使可以弄两个@Expensive, @Cheap,我也没办法用组合@Cheap @ForSnowShovelling来表达“便宜的雪铲”这个概念。我只能写@CheapForSnowShovelling。:-(

6。你可以注射List<String>, List<Integer>, List<Map<String, Iterable<Object>>>,都行,但是,不能注射List<T>,不能注射List<? extends Closeable>。也就是说,不支持wildcard,并且类型参数必须是具体的,而不是T。

7。Guice的fluent interface api用起来还成。但是mock测试起来(写扩展的时候,不是应用)比较麻烦,看javadoc也比较复杂,要看那一堆名字好长好长的中间Builder对象的文档。

8。没有lifecycle,至少destroy或者PreDestroy还是有用的。


大致就想到这么多。



第四点貌似可以用scope+proxy来解决
   
0 请登录后投票
最后更新时间:2008-03-23
在Spring 2.5发布这么久以后,还进行这样的讨论,真是让人费解。
   
0 请登录后投票
最后更新时间:2008-03-23
都08年了,还有人谈Spring这么古老的东西,真是让人费解。
   
0 请登录后投票
最后更新时间:2008-03-24
偶觉得国内比国外落后个几年很正常的...落后一个世纪都可以呢,何况是几年?
   
0 请登录后投票
最后更新时间:2008-03-24
ajoo 写道
都08年了,还有人谈Spring这么古老的东西,真是让人费解。


呵呵, 好像变化是挺快的, 现在都不大讨论Hibernate, Spring 这些东东了.
   
0 请登录后投票
最后更新时间:2008-03-24
icess 写道
ajoo 写道
都08年了,还有人谈Spring这么古老的东西,真是让人费解。


呵呵, 好像变化是挺快的, 现在都不大讨论Hibernate, Spring 这些东东了.


我在2003年3月就开始谈Hibernate,2003年11月就开始谈Spring。我都嚼来嚼去嚼了五年了,你还要逼我再谈spring/hibernate,还是饶了我吧。
   
0 请登录后投票
最后更新时间:2008-03-24
谈Spring的时候,EJB的卫道士们反对
谈Guice了,Spring的卫道士们反对.
历史总是惊人地相似.
   
0 请登录后投票
最后更新时间:2008-03-24
blogbin 写道
java领域同类的东西太多,而不是太少,大量的精力都花在选择哪个框架。
搞不好,几年之后,guice也和现在spring一样臃肿不堪。

你花大量的精力选框架???真是闲啊.
   
0 请登录后投票
论坛首页 Java版

跳转论坛:
JavaEye推荐