Google Guice 高级教程02 - Guice的IOC容器(1)

Google Guice 高级教程02 - Guice的IOC容器(1)

6 Guice的IOC容器

6.1 注入过程

在前面的教程中我们讲了Guice注入例子,在使用上具体描述了Guice的注入过程。在下面的篇幅中我们从源码级了解了Guice的注入过程。

我们从具体到抽象再到具体的深入了解Guice的内部运作机制 。

下面一张序列图就是描述了Guice最简单的一次注入过程。比如下面的例子是我们熟悉的。

 1  public   class  HelloWorldDemo {
 2       public   static   void  main(String[] args) {
 3          Injector inj  =  Guice.createInjector( new  Module() {
 4              @Override
 5               public   void  configure(Binder binder) {
 6                  binder.bind(HelloWorld. class ).to(HelloWorldImpl. class );
 7              }
 8          });
 9          HelloWorld hw  =  inj.getInstance(HelloWorld. class );
10          hw.sayHello();
11           //
12      }
13  }

 

 

Google Guice 高级教程02 - Guice的IOC容器(1)_第1张图片

从上面的图像可以看到我们的核心是Guice如何将我们的实例注入到Injector中的,这样客户端才能在Injector查找我们需要的服务。

我们进入Guice的createInjector方法,看看Guice到底做了什么操作。

public   static  Injector createInjector(Module modules) {
    
return  createInjector(Arrays.asList(modules));
  }
   
public   static  Injector createInjector(Iterable <?   extends  Module >  modules) {
    
return  createInjector(Stage.DEVELOPMENT, modules);
  }
  
public   static  Injector createInjector(Stage stage, Module modules) {
    
return  createInjector(stage, Arrays.asList(modules));
  }
  
public   static  Injector createInjector(Stage stage,
      Iterable
<?   extends  Module >  modules) {
    
return   new  InjectorBuilder()
        .stage(stage)
        .addModules(modules)
        .build();
  }

 

从上面的代码可以看到我们的Injector是被InjectorBuilder以Builder的模式构造出来的。同时我们也可以注入多个Module,并且默认情况下Guice是以Stage.DEVELOPMENT模式运行的。

在进入我们最核心的InjectorBuilder之前,我们先简化下模型。所谓的IOC容器,或者说DI容器,我们可以看做是一个特殊的Map,这个Map能够将我们的对象按照某种Key(键值)的方式存入,然后客户端能够根据Key来获取我们的对象。因此为了了解Guice容器的内部结构,我们先要了解下Guice容器中存放一个对象的Key到底是什么。

6.2 容器Key

在Guice中用com.google.inject.Key<T>对象来描述一个实例可以对应的Key。

我们可以想象,如果我们以某种类型来从Map中获取结果,那么对于同一种类型每次获取的结果就一样。看似满足需求。但是如果某一种类型对应多种实例怎么办?这种情况下我们就需要我们的Key不仅支持类型,还附带另外一点点东西。Guice是完全基于Annotation的,没有类似spring那样唯一id的概念,于是在Guice中描述一个Key就是靠类型和注解来完成的。在基础教程中我们看到了对于同一种类型,加了不同的注解获取的就是不同的实例。

在Java中每一个对象都有一个类型的概念,即使私有类型比如int,boolean也是有类型的概念,但是自从Java 5推出泛型以后,一直没有一种描述泛型的类型。比如说List<String>在Java中使用List类型来描述的。但是尽管JVM有运行时擦除泛型的特点,却又有能够获取编译前类型的特性,因此实际上List<String>和List<Integer>对于我们来说应该是两种不同的类型。

Guice自创造了一种描述类型的方式,包括泛型类型。在Guice中使用com.google.inject.TypeLiteral<T>类描述所有的类型(包括泛型类型)。我们可以写一个小的例子来看看。

/**
* $Id: TypeLiteralDemo.java 110 2010-01-08 03:06:53Z xylz $
* xylz study project (www.imxylz.cn)
*/
package  cn.imxylz.study.guice.inner;
import  java.lang.reflect.Method;
import  java.util.HashMap;
import  java.util.Map;
import  com.google.inject.TypeLiteral;
/**  a demo for using { @link  TypeLiteral}
@author  xylz (www.imxylz.cn)
@version  $Rev: 110 $
*/
public   class  TypeLiteralDemo {
    
public   static   void  main(String[] args)  throws  Exception{
        
//
        System.out.println(String.format( " guice type:%s " , TypeLiteral.get(Boolean. class )));
        System.out.println(String.format(
" java type:%s " , Boolean. class ));
        System.out.println();
        
//
        System.out.println(String.format( " guice type:%s " , TypeLiteral.get( int . class )));
        System.out.println(String.format(
" java type:%s " int . class ));
        System.out.println();
        
//
        System.out.println(String.format( " guice type:%s " new  TypeLiteral < Map < Integer, String >> (){}));
        System.out.println(String.format(
" java type:%s " new  HashMap < Integer,String > ().getClass()));
        System.out.println();
        
//
        Method m  =  Map. class .getMethod( " keySet " new  Class[ 0 ]);
        System.out.println(String.format(
" java type:%s " , m.getReturnType()));
        System.out.println(String.format(
" java generic type:%s " , m.getGenericReturnType()));
        System.out.println(String.format(
" guice type:%s " , TypeLiteral.get(m.getGenericReturnType())));
        System.out.println();
        TypeLiteral
< Map < Integer, String >>  mapType  =   new  TypeLiteral < Map < Integer, String >> () {};
        System.out.println(String.format(
" guice type:%s " , mapType.getReturnType(m)));
    }
}

 

下面是一次输出结果。

guice type:java.lang.Boolean
java type:
class  java.lang.Boolean
guice type:
int
java type:
int
guice type:java.util.Map
< java.lang.Integer, java.lang.String >
java type:
class  java.util.HashMap
java type:
interface  java.util.Set
java generic type:java.util.Set
< K >
guice type:java.util.Set
< K >
guice type:java.util.Set
< java.lang.Integer >

 

从上面的结果可以看出,Java通过一些反射机制描述了部分泛型的类型(使用java.lang.reflect.ParameterizedType来描述,其它类型使用java.lang.reflect.Type来描述,注意Class是实现了Type接口的),但是并不完整,因此Guice重写了这部分。

 

Google Guice 高级教程02 - Guice的IOC容器(1)_第2张图片

在上面的类图中我们可以看到,一个key是包含一个类型描述(TypeLiteral)和一个AnnotationStrategy的。AnnotationStrategy是由Annotation以及Annotation的类型组成。而TypeLiteral包含私有类型Class和对Key的引用的。

总之在Guice中是通过类型描述和注解(Key)来完整实例描述的,通过一个Key就我们能够从Guice容器(Injector)中获取我们需要的实例,至于这个实例是单个实例还是一组实例(Set或者Map类型的实例),后面会继续探讨。

上一篇:Google Guice 高级教程01 - 源码目录

下一篇:待续



©2009-2014 IMXYLZ
imxylz.com
| 求贤若渴

你可能感兴趣的:(Google Guice 高级教程02 - Guice的IOC容器(1))