最近在研讀Hive社區(qū)版本的源碼媳板,發(fā)現(xiàn)其中多處用到了Java依賴注入椭豫,這里簡單總結一下依賴注入的幾種實現(xiàn)方法慎王。在談java依賴注入之前浆熔,有必要先回顧一下設計模式中的Proxy模式本辐。
其實每個模式名稱就表明了該模式的作用,代理模式就是多一個代理類出來医增,替原對象進行一些操作慎皱,比如我們在租房子的時候回去找中介,為什么呢叶骨?因為你對該地區(qū)房屋的信息掌握的不夠全面茫多,希望找一個更熟悉的人去幫你做,此處的代理就是這個意思忽刽。再如我們有的時候打官司天揖,我們需要請律師,因為律師在法律方面有專長跪帝,可以替我們進行操作今膊,表達我們的想法。先來看看關系圖:
根據(jù)上文的闡述伞剑,代理模式就比較容易的理解了斑唬,我們看下代碼:
public interface Sourceable {
public void method();
}
@Override
public void method() {
System.out.println("the original method!");
}
public class Proxy implements Sourceable {
private Source source;
public Proxy(){
super();
this.source = new Source();
}
@Override
public void method() {
before();
source.method();
atfer();
}
private void atfer() {
System.out.println("after proxy!");
}
private void before() {
System.out.println("before proxy!");
}
}
測試類
public class ProxyTest {
public static void main(String[] args) {
Sourceable source = new Proxy();
source.method();
}
}
輸出:
before proxy!
the original method!
after proxy!
代理模式的應用場景:
如果已有的方法在使用的時候需要對原有的方法進行改進,此時有兩種辦法:
1、修改原有的方法來適應赖钞。這樣違反了“對擴展開放,對修改關閉”的原則聘裁。
2雪营、就是采用一個代理類調用原有的方法,且對產(chǎn)生的結果進行控制衡便。這種方法就是代理模式献起。
使用代理模式,可以將功能劃分的更加清晰镣陕,有助于后期維護谴餐!
下面我們要說的Java依賴注入可以說就是proxy模式的一種應用,這里總結一下常用的三種依賴注入方法
1. 接口注入
我們常常借助接口來將調用者與實現(xiàn)者分離呆抑。如:
public class ClassA {
private InterfaceB clzB;
public init() {
Ojbect obj =
Class.forName(Config.BImplementation).newInstance();
clzB = (InterfaceB)obj;
}
……
}
上面的代碼中岂嗓,ClassA依賴于InterfaceB 的實現(xiàn),如何獲得InterfaceB 實現(xiàn)類的實例鹊碍?傳統(tǒng)的方法是在代碼中創(chuàng)建InterfaceB 實現(xiàn)類的實例厌殉,并將起賦予clzB。而這樣一來侈咕,ClassA在編譯期即依賴于InterfaceB 的實現(xiàn)公罕。為了將調用者與實現(xiàn)者在編譯期分離,于是有了上面的代碼耀销,我們根據(jù)預先在配置文件中設定的實現(xiàn)類的類名楼眷,動態(tài)加載實現(xiàn)類,并通過InterfaceB 強制轉型后為ClassA所用熊尉。
這就是接口注入的一個最原始的雛形罐柳。而對于一個接口注入型IOC容器而言,加載接口實現(xiàn)并創(chuàng)建其實例的工作由容器完成帽揪,如J2EE開發(fā)中常用的Context.lookup(ServletContext.getXXX)硝清,都是接口注入型IOC的表現(xiàn)形式。
Apache Avalon是一個典型的Type1型IOC容器转晰。
2. 構造子注入
構造子注入芦拿,即通過構造函數(shù)完成依賴關系的設定,如:
public class DIByConstructor {
private final DataSource dataSource;
private final String message;
public DIByConstructor(DataSource ds, String msg) {
this.dataSource = ds;
this.message = msg;
}
……
}
可以看到查邢,在Type2類型的依賴注入機制中蔗崎,依賴關系是通過類構造函數(shù)建立,容器通過調用類的構
造方法扰藕,將其所需的依賴關系注入其中缓苛。
PicoContainer(另一種實現(xiàn)了依賴注入模式的輕量級容器)首先實現(xiàn)了Type2類型的依賴注入模式。
3. 設置注入
這種方式廣泛應用在Spring框架的參數(shù)配置中,客戶代碼僅僅面向接口編程未桥,而無需知道實現(xiàn)類的具體名稱笔刹。同時,我們可以很簡單的通過修改配置文件來切換具體的底層實現(xiàn)類冬耿。下面我們拋開Spring框架本身舌菜,使用一個簡單的例子來實現(xiàn)類似Spring的依賴注入
public class ActionFactory {
public static Action getAction(String actionName) {
Properties pro = new Properties();
try {
pro.load(new FileInputStream("config.properties"));
String actionImplName = (String) pro.get(actionName);
String actionMessage = (String) pro.get(actionName + "_msg");
Object obj = Class.forName(actionImplName).newInstance();
// BeanUtils是Apache Commons BeanUtils提供的輔助類
BeanUtils.setProperty(obj, "message", actionMessage);
return (Action) obj;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
配置文件則采用最簡單的properties文件形式:
TheAction=net.xiaxin.spring.qs.UpperAction
TheAction_msg=HeLLo
測試類:
public void testFactory(){
Action action = ActionFactory.getAction("TheAction");
System.out.println(action.execute("Rod Johnson"));
}
上面的例子中,我們通過設置注入亦镶,在運行期動態(tài)將字符串“HeLLo” 注入到Action實現(xiàn)類的Message屬性中日月。用同樣的方法,我們可以通過修改配置文件讓程序調用不同的實現(xiàn)方法缤骨,從而實現(xiàn)靈活的依賴注入爱咬。在Hive源碼中,HiveDriverRunHook類也是使用這種方式實現(xiàn)注入的