Guice可以缓和对于"工厂"和"new"关键字的依赖,将@Inject作为new来看待。可能还是会用到一些和工厂相关的,但是代码并不会直接依赖它们。甚至不客气地可以说,Guice是core java里面一个missing feature.
1.Motivation
首先,你并不想把所有的代码都写到一起。于是应这个形式,各个data,service,classes的连接方式也多种多样。总是使用new,即使是工厂,总得还要写一些set,remove方法进行初始化,将来要改代码又得分别去代码里面改,比较混乱。
2.Dependency Injection (依赖注入)
也就是说将一个接口绑定到具体的类中,这样的话,客户端就不用关心具体的实现,只需要获取相应的接口完成其服务就行了。
写一个接口,里面写一些方法,然后写一个实现类,将方法全部实现。使用的是Annotation,而不是传统意义上的xml或者properties文件。
在实现类中,将一些需要使用到的Service作为成员变量,然后在其构造函数中将这些变量初始化。这样就可以通过构造函数的方式将dependencies传给对象,让对象初始化。
注意,需要在构造函数的上方加上@Inject的注解。
所有的操作都只跟接口有关,真正的实现类只是通过一个配置文件绑定好就行了。
3.使用
然后在真正的功能类中,想要使用的时候,先声明一个Injector
Injector injector = Guice.createInjector(里面放一个Module接口的实现类,或者其它抽象类比如AbstractModule的子实现类),Module类的实现类必须实现configure(Binder binder)方法,
即
public class XXXModule extends AbstracModule{
@Override
public void configure(Binder binder){
binder.bind(接口.class).to(实现类.class); //不可以自己绑定自己
xxx,这里可以全部一起绑定了,相当于配置
}
}
比如: bind.(Service.class).to(ServiceImpl.class);
注意:
1.Guice不允许绑定多个实现在一个接口上,所以实现可以写很多个,但是真正配置的时候,只能绑定一个。这个是可以理解的,
试想,你在找实现类的时候总要有一种机制保证到底使用哪一种吧,不可能都使用。
试想,你在找实现类的时候总要有一种机制保证到底使用哪一种吧,不可能都使用。
2.绑定可以级联,也就是bind(A).to(B); bind(B).to(C),那么,在你调用A的时候,就会返回C的实例。
然后当你需要调用的时候,定义一个接口类型的变量,并且赋值
接口类
Service service= injector.getInstance(Service.class);
这样就相当于把ServiceImpl的实例(也就是自己事先绑定好的实现)传了过来,然后再调用里面的方法
总结一下,意思就是,将一个ServiceImpl的实例和Service关联起来,当向Guice请求获取一个Service实例的时候,Guice就返回一个ServiceImpl的实例,然后就可以调用Service里面的方法了。这样就不用老是去new了,直接按照接口的定义使用就行了,关联哪一个实现类,自己事先绑定好就是了。
1) @Singleton
使用Injector默认的配置的话,每次Guice都会返回一个新的实例,有时候可能并不希望总是这样。很多时候需要使用单例模式(事实上我觉得很多估计都是单例吧。
a.就直接在
实现类的类名前面一行加上一个@Singlton标注一下就行
比如
@Singleton
public class ServiceImpl implements Service{
xxx
xxx
}
b.还可以通过bind的statement来进行,比如bind(Service.class).to(ServiceImpl.class).in(Singleton.class);
注意:当然,ServiceImpl可以被多个Service绑定,所以,假如有2个不同的Service绑定了ServiceImpl,那么就会创建2个ServiceImpl的实例。
2) @Inject
可以注入构造方法,主要的目的,应该是参数传递。往往实现类中会定义一些成员变量,这些成员变量很可能就是一些接口,然后通过注入构造函数将它们和一些实现类绑定。这样同样也是有个好处,代码维护成本低。试想,你本来使用着一个框架,但是突然小组决定更换框架,这个时候使用注入只需要改一下绑定配置就行了。
反正知道这么个原理就行,注入一些和服务有关系的,服务本身,或者将服务作为参数的构造函数。然后绑定好,通过调用injector来获取实例,使用服务。
4.Bindings
还是那个意思,injector的工作就是说将对象装配起来,你请求获取某个类型的实例,然后injector就会去找到它,并且返回给你。
怎样创建bindings呢? 写一个module类,继承AbstractModule抽象类,重写它的configure方法。然后在这个方法里面,你可以调用bind()方法来进行绑定。在你进行绑定的时候,它会给你提示,如果你的接口和实现类不匹配的话,就会报错。一旦这个module类创建好了,你就可以在创建injectot的时候将它作为参数了。