----------- android培訓、java培訓、java學習型技術博客、期待與您交流! -----------
一 代理的概念與作用
程序中的代理
要爲已經存在的多個具有相同接口的目標類的各個方法增加一些系統功能,例如,異常處理、、日誌、計算方法的運行時間、事務管理等等,該如何做》
編寫一個與目標類具有相同接口的代理類,代理類的每個方法調用目標類的相同方法,並在調用方法時加上系統功能的代碼
如果採用工廠模式和配置文件的方式進行管理,則不需要修改客戶端程序,在配置文件中配置是使用目標類還是代理類,這樣以後很容易切換,比如,想要日誌功能時就配置代理類,否則配置目標類,這樣增加系統功能很容易,以後運行一段時間,又想去掉系統功能也很容易。
AOP Aspect oriented program 面向方面的編程
二 動態代理技術
要爲系統中的各種接口的類增加代理功能,那將需要太多的代理類,全部採用靜態代理方式,將是一件非常麻煩的事情,寫成百上千個代理類
JVM可以在運行期動態生成出類的字節碼,這種動態生成的類往往被用作代理類,即動態代理類
JVM生成的動態類必須實現一個或多個接口,所以,JVM生成的動態類只能用作具有相同接口的目標類的代理。
如果目標類沒有實現一個接口,那麼CGLIB庫可以動態生成一個類的子類,一個類的子類也可以用作該類的代理,所以,如果要爲一個沒有實現接口的類生成動態代理類,那麼可以便用CGLIB庫
代理類的各個方法中通常除了要調用目標的響應方法和對外返回目標返回的結果,還可以在代理方法中的如下四個位置加上系統功能代碼:
在調用目標方法之前
在調用目標方法之後
在調用目標方法前後
在處理目標方法異常的catch塊中
三 分析JVM動態生成的類
創建實現了Collection接口的動態類和查看其名稱,分析Proxy.getProxyClass方法的各個參數
編碼列出動態類中的所有構造方法和參數名
編碼列出動態類中所有的方法和參數名
創建動態類的實例對象
1、用反射獲得構造方法
2、編寫一個最簡單的invocationHandler類
3、調用構造方法創建動態類的實例對象,並將編寫的invocationHandler類的實例對象傳進去
4、打印創建的對象和調用對象的沒有返回值的方法和getClass方法,演示調用其他有返回值的方法報告了異常
5、 將創建動態類的實例對象代理該次匿名內部類的形式填寫,
總結思考,讓jvm創建動態類及其實例對象,需要給它提供哪些信息
三個方面:
生成的類中有哪些方法,通過讓其實現哪些接口的方式進行告知
產生的類字節碼必須有個一個關聯的類加載器對象
生成的類中的方法的代碼是怎麼樣的,也得由我們提供,把我們的代碼寫在一個約定好了接口對象的方法中,把對象傳給它,它調用我的方法,即相當於插入了我的代碼,提供執行代碼的對象就是那個InvocationHandler對象,它是在創建動態類的實例對象的構造方法時傳遞進去的,在上面的InvocationHandler對象的invoke方法中加一點代碼,就可以看到這些代碼被調用運行了
用Proxy.newInstance方法直接一步就創建出代理對象
猜想分析動態生成的類的內部代碼
動態生成的類實現了Collection接口(可以實現若干接口),生成的類有Collection接口中的所有方法和一個如下接收InvocationHandler參數的構造方法。
構造方法接收一個InvocationHandler對象,接收對象了要幹什麼用?該方法內部代碼是怎麼樣實現的?
$Proxy0 implements Collection
{
InvocationHandler handler;
public $Proxy0(InvocationHandler handler)
{
this.handler = handler;
}
}
實現的Collection接口中的各個方法的代碼是怎麼樣的?InvocationHandler接口中定義的invoke方法接收的三個參數是什麼意思?
int size()
{
return handler.invoke(this,this.getClass().getMethod("size"),null);
}
說明:
Client 程序調用objproxy.add("aaa")方法時,涉及三要素:objProxy對象,add方法,"aaa"參數。
Class Proxy$
{
add(Object object)
{
return handler.invoke(Object proxy,Method method,Object[] args),
}
}
四分析動態代理的工作原理圖
怎樣將目標類傳進去?
直接在InvocationHandler實現類中創建目標類的實例對象,可以看運行效果和加入日誌代碼,但沒有實際意義。
爲InvocationHandler實現類注入目標類的實例對象,不能採用匿名內部類的形式了。
讓匿名的InvocationHandler實現類訪問外面方法中的目標類實例對象的final類型的引用變量。
將創建代理的過程改爲一種更優雅的方式,eclipse重構出一個getProxy方法綁定接收目標同時返回代理對象,讓調用者更懶惰,更方便,調用者甚至不用接觸任何代理的API。
將系統功能代碼模塊化,即將切面代碼頁改爲通過參數形式提供,怎樣把要執行的系統功能代碼以參數形式提供?
把要執行的代碼裝到一個對象的某個方法裏,然後把這個對象作爲參數傳遞,接受者只要調用這個對象的方法,即等於執行了外界提供的代碼。
爲bind方法增加一個Advice參數。