所谓的绑定就是将一个接口绑定到具体的类中,这样客户端不用关心具体的实现,而只需要获取相应的接口完成其服务即可。
helloworld.java
public interface helloworld {
string sayhello();
}
然后是具体的实现,helloworldimpl.java
public class helloworldimpl implements helloworld {
@override
public string sayhello() {
return "hello, world!";
}
写一个测试例子看看,helloworldtest.java
public class helleworldtest {
@test
public void testsayhello() {
injector inj= guice.createinjector(new module() {
@override
public void configure(binder binder) {
binder.bind(helloworld.class).to(helloworldimpl.class);
}
});
helloworld hw = inj.getinstance(helloworld.class);
assert.assertequals(hw.sayhello(), "hello, world!");
}
}
这个例子非常简单,通俗的将就是将一个helloworldimpl的实例与helloworld关联起来,当想guice获取一个helloworld实例的时候,guice就返回一个helloworldimpl的实例,然后我们就可以调用helloworld服务的方法了。
自我分析:针对于factory工厂类的框架整合!
问题(1)helloworld是单例的么?测试下。
helloworld hw = inj.getinstance(helloworld.class);
assert.assertequals(hw.sayhello(), "hello, world!");
helloworld hw2 = inj.getinstance(helloworld.class);
system.out.println(hw.hashcode()+"->"+hw2.hashcode());
assert.assertequals(hw.hashcode(), hw2.hashcode());
解答(1)测试结果告诉我们,helloworld不是单例的,每次都会返回一个新的实例。
问题(2)helloworld的实例是helloworldimpl么?可以强制转型么?
helloworld hw = inj.getinstance(helloworld.class);
system.out.println(hw.getclass().getname());
解答(2),
结果输出
cn.imxylz.study.guice.helloworld.helloworldimpl,看来确实只是返回了一个正常的实例,并没有做过多的转换和代理。
问题(3),如果绑定多个实现到同一个接口上会出现什么情况?
public class helloworldimplagain implements helloworld {
@override
public string sayhello() {
return "hello world again.";
}
binder.bind(helloworld.class).to(helloworldimpl.class);
binder.bind(helloworld.class).to(helloworldimplagain.class);
解答(3),很不幸,guice目前看起来不允许多个实例绑定到同一个接口上了。
com.google.inject.creationexception: guice creation errors:
1) a binding to cn.imxylz.study.guice.helloworld.helloworld was already configured at cn.imxylz.study.guice.helloworld.helleworldtest$1.configure(helleworldtest.java:28).
at cn.imxylz.study.guice.helloworld.helleworldtest$1.configure(helleworldtest.java:29)
问题(4),可以绑定一个实现类到实现类么?
injector inj= guice.createinjector(new module() {
@override
public void configure(binder binder) {
binder.bind(helloworldimpl.class).to(helloworldimpl.class);
});
helloworld hw = inj.getinstance(helloworldimpl.class);
system.out.println(hw.sayhello());
非常不幸,不可以自己绑定到自己。
1) binding points to itself.
at cn.imxylz.study.guice.helloworld.helleworldtest$1.configure(helleworldtest.java:28)
我们来看看bind的语法。
<t> annotatedbindingbuilder<t> bind(class<t> type);
scopedbindingbuilder to(class<? extends t> implementation);
也就是说只能绑定一个类的子类到其本身
。改造下,改用子类替代。
public class helloworldsubimpl extends helloworldimpl {
@override
public string sayhello() {
return "@helloworldsubimpl";
}
injector inj = guice.createinjector(new module() {
@override
public void configure(binder binder) {
binder.bind(helloworldsubimpl.class).to(helloworldsubimpl.class);
}
});
helloworldimpl hw = inj.getinstance(helloworldimpl.class);
system.out.println(hw.sayhello());
支持子类绑定,这样即使我们将一个实现类发布出去了(尽管不推荐这么做),我们在后期仍然有办法替换实现类。
使用bind有一个好处,由于java 5以上的泛型在编译器就确定了,所以可以帮我们检测出绑定错误的问题,而这个在配置文件中是无法检测出来的。
这样看起来module像是一个map,根据一个key获取其value,非常简单的逻辑。
问题(5),可以绑定到我们自己构造出来的实例么?
解答(5)当然可以!看下面的例子。
@override
public void configure(binder binder) {
binder.bind(helloworld.class).toinstance(new helloworldimpl());
}
});
helloworld hw = inj.getinstance(helloworld.class);
问题(6),我不想自己提供逻辑来构造一个对象可以么?
解答(6),可以guice提供了一个方式(provider<t>),允许自己提供构造对象的方式。
injector inj= guice.createinjector(new module() {
public void configure(binder binder) {
binder.bind(helloworld.class).toprovider(new provider<helloworld>() {
public helloworld get() {
return new helloworldimpl();
});
helloworld hw = inj.getinstance(helloworld.class);
system.out.println(hw.sayhello());
问题(7),实现类可以不经过绑定就获取么?比如我想获取helloworldimpl的实例而不通过module绑定么?
解答(7),可以,实际上guice能够自动寻找实现类。
injector inj= guice.createinjector();
问题(8),可以使用注解方式完成注入么?不想手动关联实现类。
解答(8),好,guice提供了注解的方式完成关联。我们需要在接口上指明此接口被哪个实现类关联了。
@implementedby(helloworldimpl.class)
public interface helloworld {
string sayhello();
}
事实上对于一个已经被注解的接口我们仍然可以使用module来关联,这样获取的实例将是module关联的实例,而不是@implementedby注解关联的实例。这样仍然遵循一个原则,手动优于自动。
问题(9)再回头看问题(1)怎么绑定一个单例?
injector inj = guice.createinjector(new module() {
@override
public void configure(binder binder) {
binder.bind(helloworld.class).to(helloworldimplagain.class).in(scopes.singleton);
}
});
helloworld hw2 = inj.getinstance(helloworld.class);
system.out.println(hw.hashcode() + "->" + hw2.hashcode());
可以看到现在获取的实例已经是单例的,不再每次请求生成一个新的实例。
事实上guice提供两种scope,
com.google.inject.scopes.singleton和com.google.inject.scopes.no_scope,
所谓没有scope即是每次生成一个新的实例。
对于自动注入就非常简单了,只需要在实现类加一个singleton注解即可。
@singleton
public class helloworldimpl implements helloworld {
@override
public string sayhello() {
return "hello, world!";