Guice(pronounced “juice”)发布了1.0版本.
首先看看Guice的定位:an ultra-lightweight, next-generation dependency injection container for Java 5 and later.
这是一个基于Java 5及后续版本的轻量级依赖注入容器。Martin Fowler关于依赖注入的精彩讨论参见:http://www.martinfowler.com/articles/injection.html#InversionOfControl
在这篇讨论中涉及到几种注入方式:Constructor Injection、Setter Injection、Interface Injection;
实际应用开发中依赖的注入问题自始至终都伴随着我们,当我们走过了最简单直接的手动注入、运用模式进行注入,到依赖于框架,当前成熟的框架众多,例如:Spring IOC、PicoContainer、Hivemind等;那么Guice作为一个依赖注入的framework,又是怎么定位自己的呢?其special的地方又在哪儿呢?我们首先看一个非常简单的例子:
对于注入描述的类如下:
public class MyModule implements Module {
    public void configure(Binder binder) {
        binder.bind(Service.class).to(ServiceImpl.class).in(Scopes.SINGLETON);
    }
}
依赖注入发生的地方:
public class Client {
    private final Service service;
    @Inject
    public Client(Service service) {
        this.service = service;
    }
    public void go() {
        service.go();
    }
}
从这个例子我们可以清晰看出,Guice的依赖注入已经不同于以往的三种注入模式了,Okey,你已经看到了Guice充分使用了Java的新特性annotation来进行依赖注入的,已经完全跨越了Constructor Injection、Setter Injection、Interface Injection的概念了。这样,依赖注入只是需要一个或者多个annotation而已,一切搞定。
下一步我看看Guice这个Framework是要如何进行依赖注入的?
我们首先看看Guice的Architecture.
public class MyModule implements Module {
    public void configure(Binder binder) {
        // Bind Foo to FooImpl. Guice will create a new
        // instance of FooImpl for every injection.
        binder.bind(Foo.class).to(FooImpl.class);
        // Bind Bar to an instance of Bar.
        Bar bar = new Bar();
        binder.bind(Bar.class).toInstance(bar);
    }
}
该部分代码的sequence diagram如下:
运行时Guice的依赖注入的绑定器structure如下:
很明显的看到,一个注入的绑定关联主键Key、Scope、Provider;其中Key包含了依赖的Type和Annotation.
看到了Guice的简单绑定,一定会有一个疑问:就是一个类型的多个绑定怎么实现?Guice是运行Annotation binding来解决这个问题的。
例如绑定代码如下:
public class BindingModule implements Module {
    public void configure(Binder binder) {
        binder.bind(IService.class).annotatedWith(Blue.class).to(BlueService.class);
    }
}
注入代码如下:
public class BindingClient {
    // @Inject
    // @Blue
    // private IService service;
    private IService service;
    @Inject
    public void injectService(@Blue IService service) {
        this.service = service;
    }
    public void go() {
        this.service.go();
    }
}
annotation部分代码:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@BindingAnnotation
public @interface Blue {
}
如果再复杂一些,Guice还支持有属性的annotation:
绑定代码
public class NamedModule implements Module {
/*
* (non-Javadoc)
* 
* @see com.google.inject.Module#configure(com.google.inject.Binder)
*/
public void configure(Binder binder) {
    binder.bind(IPerson.class).annotatedWith(new NamedAnnotation("Bob")).to(Bob.class);
}
}
注入代码:
public class NamedClient {
    @Inject
    @Named("Bob")
    private IPerson person;
    public void say(){
        this.person.say();
    }
}
annotation代码:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@BindingAnnotation
public @interface Named {
    String value();
}
public class NamedAnnotation implements Named {
    private String value;
    public NamedAnnotation(String value){
        this.value = value;
    }
    /*
    * (non-Javadoc)
    * 
    * @see com.neusoft.anno.Named#value()
    */
    public String value() {
        return value;
    }
    public int hashCode() {
        return 127 * "value".hashCode() ^ value.hashCode();
    }
    public boolean equals(Object o) {
    if (!(o instanceof Named))
        return false;
        Named other = (Named) o;
        return value.equals(other.value());
    }
    public String toString() {
        return "@" + Named.class.getName() + "(value=" + value + ")";
    }
    /*
    * (non-Javadoc)
    * 
    * @see java.lang.annotation.Annotation#annotationType()
    */
    public Class annotationType() {
        return Named.class;
    }
}
通过这几个例子,可以清晰看到,Guice应用annotation进行注入的关联的,用module将依赖关系组装起来,提供给客户端代码进行使用;而且annotation是可以自由定制的,支持灵活扩展的。
Guice本身也支持实现类的直接绑定:
public class MixerModule implements Module {
    /*
    * (non-Javadoc)
    * 
    * @see com.google.inject.Module#configure(com.google.inject.Binder)
    */
    public void configure(Binder binder) {
        binder.bind(Concrete.class);
    }
}
Guice有一种隐式绑定,其方法是这样,针对一个接口,如果缺少显式绑定,Guice 会寻找一个指向具体实现的@ImplementedBy标注。
@ImplementedBy(GoodNightImpl.class)
    public interface IGoodNight {
    void goodNight();
    }
    @Singleton
    public class GoodNightImpl implements IGoodNight {
    /*
    * (non-Javadoc)
    * 
    * @see com.neusoft.nobinding.IGoodNight#goodNight()
    */
    public void goodNight() {
        System.out.println("Good night!");
    }
}
那么,Provider是怎么回事呢?“有时对于每次注入,客户代码需要某个依赖的多个实例。其它时候,客户可能不想在一开始就真地获取对象,而是等到注入后的某个时候再获取。对于任意绑定类型 T,你可以不直接注入 T 的实例,而是注入一个 Provider,然后在需要的时候调用 Provider.get()”因此,可以使用Provider去真正的来创建依赖的对象实例,直到需要的时候才创建客户代码需要的实例。
Provider等绑定代码:
public class WidgetModule implements Module {
    /*
    * (non-Javadoc)
    * 
    * @see com.google.inject.Module#configure(com.google.inject.Binder)
    */
    public void configure(Binder binder) {
        binder.bind(IService.class).to(WidgetService.class).in(Scopes.SINGLETON);
        binder.bind(Widget.class).toProvider(WidgetProvider.class);
    }
}
Provider的注入:
public class Widget {
    private IService service;
    @Inject Provider provider;
    public Widget(IService service){
        this.service = service;
    }
    public void go(){
        this.service.go();
    }
}
Provider的实现:
public class WidgetProvider implements Provider {
    final IService service;
    @Inject
    WidgetProvider(IService service) {
        this.service = service;
    }
    public Widget get() {
        return new Widget(service);
    }
}
Service的接口和实现:
public interface IService {
    void go();
}
public class WidgetService implements IService {
    /* (non-Javadoc)
    * @see com.neusoft.service.IService#go()
    */
    public void go() {
        System.out.println("Widget Service Hello.");
    }
}
客户代码:
public class WidgetApplication {
    /**
    * @param args
    */
    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new WidgetModule());
        Widget widget = injector.getInstance(Widget.class);
        widget.go();
    }
}
这个例子完全表达出了Provider的价值所在。
另外,Guice也提供了Constant Values以及Converting Stings的支持:
Guice会针对Primitive types、primitive wrapper types、Strings、Enums、Classes类型进行类型的自动判断绑定机制。对于Primitive types、primitive wrapper types,如果 Guice 仍然无法找到一个的显式绑定,它会去找一个拥有相同绑定标注的常量 String 绑定,并试图将字符串转换到相应的值。
这就是一个Guice如何进行依赖注入的一个基本的思路,可以看到Guice的代码量十分少,是一个不错的依赖注入的方案,也将会推动依赖注入的进步。
参考:
Guice项目:http://code.google.com/p/google-guice/
Guice中文文档:http://docs.google.com/View?docid=dqp53rg_3hjf3ch