Google Guice 入門教程02 - 依賴注入(2)

Google Guice 入門教程02 - 依賴注入(2)
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
好了既然是入門教程,我們就不討論更深層次的東西了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章