標籤:
背景
項目中我們會遇到這樣的情況:在幾個方法中加入相同的代碼,這些代碼是與業務無關的,並且以後有可能由於考慮不周或需求變動再或者是其他原因,我們需要對他們進行逐一進行改動。舉個具體的例子,比如程式中的日誌控制、事務控制等,這些功能是與業務無關的,但卻需要將它們與我們的邏輯混在一起,達到一些特殊的需求。
這樣的情況往往代碼都是相同的,可以抽離出來,為了複用,我們可以將這些相同的代碼單獨封裝成的方法,以供其他需要的地方調用,這樣對於以後的修改就做到了只修改一處的效果,達到了程式的複用,但另外一個問題便是,將來某一天我們可能不需要這樣的功能了,我們就需要將調用這些功能的代碼逐一進行刪除,而且當方法的參數或返回值變動也許要進行每一處調用的修改。
基於以上的問題,我們可以採用代理模式進行解決。
基本介紹
代理模式(Proxy):為其他對象提供一種代理以控制對這個對象的訪問。
直白些說,我們與需要調用的目標對象之間加上一層(代理類),我們便不直接調用以前的目標對象,而是通過代理類間接調用,這樣,我們就可以在代理裡做那些抽離出的功能了。
代理模式類圖示意
以前的直接調用方式
使用代理模式抽取公用調用部分
分類
靜態:
靜態代理中的代理類是看得見摸得著的,編譯時間就已經確定了要執行的方法。靜態代理存在著代理類過多的問題。為了更加靈活度的實現,我們可以使用動態代理。
動態:代理類運行時確定
使用:
1.目標類必須實現某介面
2.建立代理對象的控制類
實現InvocationHandler,封裝根據目標對象組建代理程式類的方法,調用方首先調用Proxy的newProxyInstance方法(此部分可以應用原廠模式進行封裝,以後可以進行去除或改變代理類),產生並轉換為代理類,調用此類的目標方法,則可回調到InvocationHandler實作類別的invoke方法
樣本-動態代理封裝事務
public class TransactionHandler implements InvocationHandler {private Object targetObject;public Object newProxyInstance(Object targetObject){this.targetObject = targetObject;return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),<span style="font-family:KaiTi_GB2312;"> </span>targetObject.getClass().getInterfaces(), this);}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{Connection conn = null;Object ret = null;try{conn = ConnectionManager.getConnection();//開啟事務的配置可採用設定檔,那樣可更加靈活if(method.getName().startsWith("save") || method.getName().startsWith("remove") || method.getName().startsWith("modify")){ //手動控制事務提交 ConnectionManager.beginTransaction(conn);}//調用目標對象的商務邏輯方法ret = method.invoke(targetObject, args);//判斷,當AutoCommit設定為false的前提下控制提交if(!conn.getAutoCommit()){//提交事務ConnectionManager.commit(conn);}}catch(Exception e){e.printStackTrace();//動態代理對我們自訂的異常進行了封裝if(e instanceof InvocationTargetException){InvocationTargetException ete = (InvocationTargetException)e;throw ete.getTargetException();}//復原事務ConnectionManager.rollbackTransaction(conn);throw new ApplicationException("操作失敗!");}finally{ConnectionManager.closeConnection();}return ret;}}
註:此樣本中的類ConnectionManage具體實現參見【Java技術點滴】——ThreadLocal封裝JDBC事務操作
經過此類的封裝,我們便可以實現在Service層中需要進行事務操作的地方便不用每次都寫事務相關的代碼了,只要為Service層類組建代理程式,回調此類的的Invoke方法就可以實現事務的控制,這樣就達到了很好的複用和更高的可維護性。
總結
正因為代理模式為我們帶來了類似於Filter的攔截機制,使我們可以在調用目標方法前做一些事,在調用目標方法後做一些事,這樣就可以達到以前我們一般的編程理論所不能達到的效果,再加上一些靈活配置的附加應用,代理模式的應用可以說是相當廣泛,也為今後的程式設計提供了更多了思路與思想。
【Java技術點滴】——代理模式及其對事務封裝