程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Guice與Spring框架的區別

Guice與Spring框架的區別

編輯:關於JAVA

依賴注入,DI(Dependency Injection),它的作用自然不必多說,提及DI容器,例如spring,picoContainer,EJB容器等等,近日,google誕生了更輕巧的DI容器……Guice!

廢話不多講了,先看看Guice是如何實現注入的吧。

定義一個簡單的service接口和它的實現吧!

public interface MyService ...{
void myMethod();
}
public class MyServiceImpl implements MyService ...{
public void myMethod() ...{
System.out.println("Hello,World!");
}
}

以上是最普通的接口和其實現,沒什麼可說的。

定義一個測試類,這個類裡邊包括service對象的一個引用,這個對象是需要Guice進行注入的。

import com.google.inject.Inject;
public class Client ...{
MyService service;
@Inject //告訴容器,這裡的service對象的引用,需要進行注入
void setService(MyService service) ...{ //這裡的方法名字可以任意定義
this.service = service;
}
public void myMethod() ...{
service.myMethod();
}
}

這裡除了加了一個@Inject,和Spring的配置沒有任何的區別,@Inject,是表示對容器說,這裡的service需要注射,等到運行的時候,容器會拿來一個實例給service,完成注射的過程。

定義Guice的Module文件,告訴容器如何進行注入。

import com.google.inject.Binder;
import com.google.inject.Module;
import com.google.inject.Scopes;
public class MyModule implements Module ...{
public void configure(Binder binder) ...{
binder.bind(MyService.class).to(MyServiceImpl.class).in(Scopes.SINGLETON);
// 這句代碼的意思是說:運行時動態的將MyServiceImpl對象賦給MyService定義的對象,
而且這個對象是單例的。
}
}

創建測試類

import com.google.inject.Guice;
import com.google.inject.Injector;
public class Test ...{
public static void main(String[] args) ...{
MyModule module = new MyModule();// 定義注射規則
Injector injector = Guice.createInjector(module);// 根據注射規則,生成注射者
Client client = new Client();
injector.injectMembers(client);// 注射者將需要注射的bean,按照規則,把client這個客戶端進行注射
client.myMethod();
}
}

運行測試類,控制台輸出:Hello,World!

完成注入過程

下面看看Guice還有哪些其它的使用特性。

1、如果在實現你確定MyService定義的對象,就要被注射為MyServiceImpl而不是其它的實現類的話,可以在MyService接口加上@ImplementedBy(MyServiceImpl.class)。

import com.google.inject.ImplementedBy;
@ImplementedBy(MyServiceImpl.class)
//我總覺得這樣有點背離了依賴注入的初衷了
public interface MyService ...{
void myMethod();
}

這樣的話,在MyModule裡的configure方法中就可以不加任何東西,容器就會自動注射給MyServiceImpl對象。

2、可以對Field進行注解式注入

在Client.java中也可以把這個@Inject標注在MyService service;的前邊,如:@Inject MyService service;

3、可使用自定義Annotation標注。

package mypackage;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.google.inject.BindingAnnotation;
@Retention(RetentionPolicy.RUNTIME)
@Target( ...{ ElementType.FIELD, ElementType.PARAMETER })
@BindingAnnotation
public @interface MyInterface ...{
}

那麼Client.java需要改為:

package mypackage;
import com.google.inject.Inject;
public class Client ...{
@Inject @MyInterface MyService service;
void setService(MyService service) ...{ // 這裡的方法名字可以任意定義
this.service = service;
}
public void myMethod() ...{
service.myMethod();
}
}

MyModule.java中的configure方法內容需改為:

binder.bind(MyService.class).annotatedWith(MyInterface.class).to(
MyServiceImpl.class).in(Scopes.SINGLETON);

意思是說對於標注為MyInterface的MyService定義的對象進行注入。

進行Annotation標注的成員(Field,method,argument等)進行自定義Annotation標注,該成員既擁有該屬性,可以在運行,根據這些成員的不同屬性,做一些不同的事情,例如:spring的AspectJ,xdoclet等都是如此。

下邊是我做了一下對比:

  Spring Guice 使用XML 使用將類與類之間的關系隔離到xml中,由容器負責注入被調用的對象,因此叫做依賴注入 不使用xml,將類與類之間的關系隔離到Module中,聲名何處需要注入,由容器根據Module裡的描述,注入被調用的對象。 使用Annotation   使用

支持自定義Annotation標注,對於相同的接口定義的對象引用,為它們標注上不同的自定義Annotation注釋,就可以達到同一個類裡邊的同一個接口的引用,注射給不同的實現,在Module裡用標注做區分,靈活性大大增加。

使用Annotation也未必是好事,范型等新特性也未必是好事,目前大多的服務器均不支持jdk1.5,wls要9以前才支持,而目前的客戶由於價格原因也很少選用wls9的,至少我們做過的項目中都沒有。功能再強,客戶不需要,何用? 運行效率 裝載spring配置文件時,需解析xml,效率低,getBean效率也不高,不過使用環境不會涉及到getBean,只有生產環境的時候會用到getBean,在裝載spring應用程序的時候,已經完成全部的注射,所以這個低效率的問題不是問題。 使用Annotation,cglib, 效率高與spring最明顯的一個區別,spring是在裝載spring配置文件的時候把該注入的地方都注入完,而Guice呢,則是在使用的時候去注射,運行效率和靈活性高。 類耦合度 耦合度低,強調類非侵入,以外部化的方式處理依賴關系,類裡邊是很干淨的,在配置文件裡做文章,對類的依賴性極低。 高,代碼級的標注,DI標記@inject侵入代碼中,耦合到了類層面上來,何止侵入,簡直侵略,代碼耦合了過多guice的東西,大大背離了依賴注入的初衷,對於代碼的可維護性,可讀性均不利 類編寫時 需要編寫xml,配置Bean,配置注入 只需聲明為@inject,等著被注入,

最後在統一的Module裡聲明注入方式 僅支持IOC 否,spring目前已經涉獵很多部分 是,目前僅僅是個DI容器 是否易於代碼重構 統一的xml配置入口,更改容易 配置工作是在Module裡進行,和spring異曲同功 支持多種注入方式 構造器,setter方法 Field,構造器,setter方法 靈活性   1,如果同一個接口定義的引用需要注入不同的實現,就要編寫不同的Module,煩瑣

2,動態注入

如果你想注射的一個實現,你還未知呢,怎麼辦呢,spring是沒辦法,事先在配置文件裡寫死的,而Guice就可以做到,就是說我想注射的這個對象我還不知道注射給誰呢,是在運行時才能得到的的這個接口的實現,所以這就大大提高了依賴注射的靈活性,動態注射。 與現有框架集成度 1,高,眾多現有優秀的框架(如struts1.x等)均提供了spring的集成入口,而且spring已經不僅僅是依賴注入,包括眾多方面。

2,Spring也提供了對Hibernate等的集成,可大大簡化開發難度。

3,提供對於orm,rmi,webservice等等接口眾多,體系龐大。 1,可以與現有框架集成,不過僅僅依靠一個效率稍高的DI,就想取代spring的地位,有點難度。 配置復雜度 在xml中定位類與類之間的關系,難度低 代碼級定位類與類之間的關系,難度稍高

再借斧子的例子說一說spring與guice的區別。

看下邊對於不同社會形態下一個人(java對象,調用者)需要一把斧子(java對象,被調用者)的例子:

(1)原始社會時,勞動社會基本沒有分工,需要斧子的人(調用者)只好自己去磨一把斧子,每個人擁有自己的斧子,如果把大家的石斧改為鐵斧,需要每個人都要學會磨鐵斧的本領,工作效率極低。

對應Java裡的情形是:java程序裡的調用者new一個被調用者的實例。類耦合度極高,修改維護煩瑣,效率極低。

(2)工業社會時,工廠出現,斧子不再由普通人完成,而由工廠生產,當人們需要斧子的時候,可以到工廠購買斧子,無需關心斧子是怎麼制造出來的,如果廢棄鐵斧為鋼斧,只需改變工廠的制造工藝即可,制作工藝是工廠決定的,工廠生產什麼斧子,工人們就得用什麼斧子。

對應的Java裡的情形是:Java程序的調用者可以以來簡單工廠創建被調用者,變化點被隔離到了簡單工廠裡,雖然耦合度降低,但是調用者會和工廠耦合,而且需要定位自己的工廠。

(3)近代工業社會,工廠蓬勃發展,人們需要什麼斧子,只需要提供一個斧子圖形,商家會按照你提供的圖形將你的斧子訂做好,送上門。

對應Java裡的情形:spring的依賴注入

(4)進入按需要分配社會,信息進入現代化,人們不再去工廠購買斧子,不再拘泥於需要什麼斧子事先畫好什麼樣的圖形,只需要打個電話,描述一下需要什麼類型的斧子,或許想打造一個物美價廉的斧子,商家會根據市場零件的價格,計算出最優制作工藝,打造最適合的斧子送過來,更加信息化,更加人性化。

對應Java裡的情形:基於描述的注入,動態的,靈活簡單的注入,如:Guice。

對於該不該使用Guice,我想也是仁者見仁,智者見智,就象好多論壇裡動不動有人會在那裡討論到底學Java還是學.net或者是使用eclipse還是Jbuilder的這類無聊話題,適合和滿足項目需求的,又能省工省力簡單的完成工作的,就是最好的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved