1.2 属性注入(Field Inject)
1.2.1 基本属性注入
首先来看一个例子。Service.java
1
@ImplementedBy(ServiceImpl.
class
)
2
public
interface
Service {
3
void
execute();
4
}
ServiceImpl.java
1
public
class
ServiceImpl
implements
Service {
2
@Override
3
public
void
execute() {
4
System.out.println(
"
This is made by imxylz (www.imxylz.cn).
"
);
5
}
6
}
FieldInjectDemo.java
1
/**
a demo with Field inject
2
*
@author
xylz (www.imxylz.cn)
3
*
@version
$Rev: 71 $
4
*/
5
public
class
FieldInjectDemo {
6
@Inject
7
private
Service servcie;
8
public
Service getServcie() {
9
return
servcie;
10
}
11
public
static
void
main(String[] args) {
12
FieldInjectDemo demo
=
Guice.createInjector().getInstance(FieldInjectDemo.
class
);
13
demo.getServcie().execute();
14
}
15
}
这个例子比较简单。具体来说就是将接口Service通过@Inject注解注入到FieldInjectDemo类中,然后再FieldInjectDemo类中使用此服务而已。当然Service服务已经通过@ImplementedBy注解关联到ServiceImpl 类中,每次生成一个新的实例(非单例)。注意,这里FieldInjectDemo类没有通过Module等关联到Guice中,具体可以查看《》。
意料之中得到了我们期待的结果。
同样,我们通过问答的方式来加深理解(注意,入门教程我们只是强调怎么使用,至于原理和底层的思想我们放到高级教程中再谈)。
问题(1):可以自己构造FieldInjectDemo 对象而不通过Guice么?
1
/**
field inject demo2
2
*
@author
xylz (www.imxylz.cn)
3
*
@version
$Rev: 73 $
4
*/
5
public
class
FieldInjectDemo2 {
6
@Inject
7
private
Service servcie;
8
public
Service getServcie() {
9
return
servcie;
10
}
11
public
static
void
main(String[] args) {
12
FieldInjectDemo2 fd
=
new
FieldInjectDemo2();
13
fd.getServcie().execute();
14
}
15
}
就像上面的例子中一样,然后运行下看看?非常不幸,我们得到了一个谁都不喜欢的结果。
Exception in thread
"
main
"
java.lang.NullPointerException
at cn.imxylz.study.guice.inject.FieldInjectDemo2.main(FieldInjectDemo2.java:
22
)
很显然,由于FieldInjectDemo2不属于Guice容器(暂且称为容器吧)托管,这样Service服务没有机会被注入到FieldInjectDemo2类中。
问题(2):可以注入静态属性么?
看下面的代码。
1
public
class
FieldInjectDemo2 {
2
@Inject
3
private
static
Service servcie;
4
public
static
Service getServcie() {
5
return
servcie;
6
}
7
public
static
void
main(String[] args) {
8
FieldInjectDemo2 fd
=
Guice.createInjector().getInstance(FieldInjectDemo2.
class
);
9
FieldInjectDemo2.getServcie().execute();
10
}
11
}
很不幸!运行结果告诉我们Guice看起来还不支持静态字段注入。
好了,上面两个问题我们暂且放下,我们继续学习其它注入功能。
1.2.2 构造函数注入(Constructor Inject)
继续看例子。例子是说明问题的很好方式。
1
/**
2
* $Id: ConstructorInjectDemo.java 75 2009-12-23 14:22:35Z xylz $
3
* xylz study project (www.imxylz.cn)
4
*/
5
package
cn.imxylz.study.guice.inject;
6
7
import
com.google.inject.Guice;
8
import
com.google.inject.Inject;
9
10
/**
a demo with constructor inject
11
*
@author
xylz (www.imxylz.cn)
12
*
@version
$Rev: 75 $
13
*/
14
public
class
ConstructorInjectDemo {
15
16
private
Service service;
17
@Inject
18
public
ConstructorInjectDemo(Service service) {
19
this
.service
=
service;
20
}
21
public
Service getService() {
22
return
service;
23
}
24
public
static
void
main(String[] args) {
25
ConstructorInjectDemo cid
=
Guice.createInjector().getInstance(ConstructorInjectDemo.
class
);
26
cid.getService().execute();
27
}
28
29
}
30
31
我们在构造函数上添加@Inject来达到自动注入的目的。构造函数注入的好处是可以保证只有一个地方来完成属性注入,这样可以确保在构造函数中完成一些初始化工作(尽管不推荐这么做)。当然构造函数注入的缺点是类的实例化与参数绑定了,限制了实例化类的方式。
问题(3):构造函数中可以自动注入多个参数么?
1
public
class
ConstructorInjectDemo {
2
3
private
Service service;
4
private
HelloWorld helloWorld;
5
@Inject
6
public
ConstructorInjectDemo(Service service,HelloWorld helloWorld) {
7
this
.service
=
service;
8
this
.helloWorld
=
helloWorld;
9
}
10
public
Service getService() {
11
return
service;
12
}
13
public
HelloWorld getHelloWorld() {
14
return
helloWorld;
15
}
16
public
static
void
main(String[] args) {
17
ConstructorInjectDemo cid
=
Guice.createInjector().getInstance(ConstructorInjectDemo.
class
);
18
cid.getService().execute();
19
System.out.println(cid.getHelloWorld().sayHello());
20
}
21
}
22
23
非常完美的支持了多参数构造函数注入。当然了没有必要写多个@Inject,而且写了的话不能通过编译。
1.2.3 Setter注入(Setter Method Inject)
有了上面的基础我们再来看Setter注入就非常简单了,只不过在setter方法上增加一个@Inject注解而已。
1
public
class
SetterInjectDemo {
2
3
private
Service service;
4
5
@Inject
6
public
void
setService(Service service) {
7
this
.service
=
service;
8
}
9
10
public
Service getService() {
11
return
service;
12
}
13
14
public
static
void
main(String[] args) {
15
SetterInjectDemo sid
=
Guice.createInjector().getInstance(SetterInjectDemo.
class
);
16
sid.getService().execute();
17
}
18
19
}
20
21
好了我们再回头看问题2的静态注入(static inject)。下面的例子演示了如何注入一个静态的字段。
1
/**
a demo for static field inject
2
*
@author
xylz (www.imxylz.cn)
3
*
@version
$Rev: 78 $
4
*/
5
public
class
StaticFieldInjectDemo {
6
7
@Inject
8
private
static
Service service;
9
10
public
static
void
main(String[] args) {
11
Guice.createInjector(
new
Module() {
12
@Override
13
public
void
configure(Binder binder) {
14
binder.requestStaticInjection(StaticFieldInjectDemo.
class
);
15
}
16
});
17
StaticFieldInjectDemo.service.execute();
18
}
19
}
20
21
非常棒!上面我们并没有使用Guice获取一个StaticFieldInjectDemo实例(废话),实际上static字段(属性)是类相关的,因此我们需要请求静态注入服务。但是一个好处是在外面看起来我们的服务没有Guice绑定,甚至client不知道(或者不关心)服务的注入过程。
再回到问题(1),参考上面静态注入的过程,我们可以使用下面的方式来注入实例变量的属性。
1
public
class
InstanceFieldInjectDemo {
2
3
@Inject
4
private
Service service;
5
public
static
void
main(String[] args) {
6
final
InstanceFieldInjectDemo ifid
=
new
InstanceFieldInjectDemo();
7
Guice.createInjector(
new
Module() {
8
@Override
9
public
void
configure(Binder binder) {
10
binder.requestInjection(ifid);
11
}
12
});
13
ifid.service.execute();
14
}
15
}
16
17
实际上这里有一种简便的方法来注入字段,实际上此方法也支持Setter注入。
1
public
class
InstanceFieldInjectDemo {
2
3
@Inject
4
private
Service service;
5
public
static
void
main(String[] args) {
6
InstanceFieldInjectDemo ifid
=
new
InstanceFieldInjectDemo();
7
Guice.createInjector().injectMembers(ifid);
8
ifid.service.execute();
9
}
10
}
11
12