google guice 高级教程02 -凯发k8网页登录

关注后端架构、中间件、分布式和并发编程

   :: 凯发k8网页登录首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  111 随笔 :: 10 文章 :: 2680 评论 :: 0 trackbacks

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 }

 

 

从上面的图像可以看到我们的核心是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对象来描述一个实例可以对应的key。

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

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

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

/**
* $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重写了这部分。

 

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

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

上一篇:google guice 高级教程01 - 源码目录

下一篇:待续



©2009-2014 imxylz
|求贤若渴
posted on 2010-01-08 11:46 imxylz 阅读(27973) 评论(6)     所属分类: google guice
# re: google guice 高级教程02 - guice的ioc容器(1) 2010-01-08 12:30
顺风使舵模仿  回复  
  

# re: google guice 高级教程02 - guice的ioc容器(1) 2010-01-12 09:34
好,多谢,希望有jersey与guice结合的介绍。  回复  
  

# re: google guice 高级教程02 - guice的ioc容器(1) 2011-03-18 17:06
您觉得weld和guice哪个更具优势  回复  
  

# re: google guice 高级教程02 - guice的ioc容器(1) 2011-03-18 17:22 xylz
@forge
weld不熟悉,为了此问题特地去看了官方站点。我感觉从官方态度以及规范、支持力度来看的话weld可能比较有权威性,毕竟指定此规范jsr299()的人就是redhat自家的人。另外上面的贡献者也比较多,说明项目可能比较活跃。
guice来说由于是轻量级的,所以可能比较容易使用和受关注,而且开发者也是比较有激情的小伙子,但是官方站点,活跃度明显放缓,并且文档、知识库、论坛也不全。
结论是,从使用以及规范角度上讲选用weld(毕竟在seam中大力推广,而且jboss也有一套完整的凯发天生赢家一触即发官网的解决方案)是比较合适的,从流行技术上倒是可以关注guice。当然也不排除guice发展壮大了以至于影响整个j2ee,就像当初spring对ejb的挑战一样。  回复  
  

# re: google guice 高级教程02 - guice的ioc容器(1)[未登录] 2011-03-30 12:36
快点更新哦,博主太nb了,偶然看到这个网站,写得很好,收藏这个网址了。  回复  
  

# re: google guice 高级教程02 - guice的ioc容器(1) 2013-07-03 11:00
求持续更新。。。  回复  
  


©2009-2014
网站地图