新聞中心
?動(dòng)態(tài)代理可以提供對(duì)另一個(gè)對(duì)象的訪問,同時(shí)隱藏實(shí)際對(duì)象的具體事實(shí),代理對(duì)象對(duì)客戶隱藏了實(shí)際對(duì)象。動(dòng)態(tài)代理可以對(duì)請(qǐng)求進(jìn)行其他的一些處理,在不允許直接訪問某些類,或需要對(duì)訪問做一些特殊處理等,這時(shí)候可以考慮使用代理。目前 Java 開發(fā)包中提供了對(duì)動(dòng)態(tài)代理的支持,但現(xiàn)在只支持對(duì)接口的實(shí)現(xiàn)。

十年建站經(jīng)驗(yàn), 成都做網(wǎng)站、成都網(wǎng)站制作客戶的見證與正確選擇。成都創(chuàng)新互聯(lián)公司提供完善的營銷型網(wǎng)頁建站明細(xì)報(bào)價(jià)表。后期開發(fā)更加便捷高效,我們致力于追求更美、更快、更規(guī)范。
主要是通過 java.lang.reflect.Proxy 類和 java.lang.reflect.InvocationHandler 接口。 Proxy 類主要用來獲取動(dòng)態(tài)代理對(duì)象,InvocationHandler 接口用來約束調(diào)用者行為。
“寫一個(gè) ArrayList 類的代理,其內(nèi)部實(shí)現(xiàn)和 ArrayList 中完全相同的功能,并可以計(jì)算每個(gè)方法運(yùn)行的時(shí)間。”這是一份考題上的題目,沒有答案,來看下實(shí)現(xiàn):
- package example;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.concurrent.TimeUnit;
- /**
- * -----------------------------------------
- * @描述 TODO
- * @作者 fancy
- * @郵箱 fancydeepin@yeah.net
- * @日期 2012-8-27
- * -----------------------------------------
- */
- public class ProxyApp {
- public static void main(String[] args){
- //ArrayList代理,通過代理計(jì)算每個(gè)方法調(diào)用所需時(shí)間
- List
arrayListProxy = (List )Proxy.newProxyInstance( - ArrayList.class.getClassLoader(), /*定義代理類的類加載器,用于創(chuàng)建代理對(duì)象,不一定必須是ArrayList,也可以是其他的類加載器*/
- ArrayList.class.getInterfaces(), /*代理類要實(shí)現(xiàn)的接口列表*/
- new InvocationHandler() { /*指派方法調(diào)用的調(diào)用處理程序,這里用了匿名內(nèi)部類*/
- private ArrayList
target = new ArrayList (); //目標(biāo)對(duì)象(真正操作的對(duì)象) - /**
- * 方法描述:
- *
- * 在代理實(shí)例上處理方法調(diào)用并返回結(jié)果
- * @param proxy 代理對(duì)象(注意不是目標(biāo)對(duì)象)
- * @param method 被代理的方法
- * @param args 被代理的方法的參數(shù)集
- * @return 返回方法調(diào)用結(jié)果
- */
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- long beginTime = System.currentTimeMillis(); //開始時(shí)間
- TimeUnit.MICROSECONDS.sleep(1);
- Object obj = method.invoke(target, args); //實(shí)際調(diào)用的方法,并接受方法的返回值
- long endTime = System.currentTimeMillis(); //結(jié)束時(shí)間
- System.out.println("[" + method.getName() + "] spend " + (endTime - beginTime) + " ms");
- return obj; //返回實(shí)際調(diào)用的方法的返回值
- }
- }
- );
- arrayListProxy.add(2);
- arrayListProxy.add(4);
- System.out.println("--------- 迭代 ---------");
- for(int i : arrayListProxy){
- System.out.print(i + "\t");
- }
- }
- }
后臺(tái)打印輸出結(jié)果:
| [add] spend 2 ms [add] spend 1 ms --------- 迭代 --------- [iterator] spend 1 ms 2 4 |
從代碼上來看,用到了匿名內(nèi)部類,這樣一來,InvocationHandler 只能用一次,如果多個(gè)地方都需要用到這樣一個(gè)相同的 InvocationHandler,可以將其抽象出來成為一個(gè)單獨(dú)的類:
- package test;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.util.concurrent.TimeUnit;
- public class MyInvocationHandler implements InvocationHandler{
- private Object target; //目標(biāo)對(duì)象
- public MyInvocationHandler(Object target){
- this.target = target;
- }
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- long beginTime = System.currentTimeMillis();
- TimeUnit.MICROSECONDS.sleep(1);
- Object obj = method.invoke(target, args);
- long endTime = System.currentTimeMillis();
- System.out.println("[" + method.getName() + "] spend " + (endTime - beginTime) + " ms");
- return obj;
- }
- }
客戶端調(diào)用改成:
- package example;
- import java.lang.reflect.Proxy;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * -----------------------------------------
- * @描述 TODO
- * @作者 fancy
- * @郵箱 fancydeepin@yeah.net
- * @日期 2012-8-27
- * -----------------------------------------
- */
- public class ProxyApp {
- public static void main(String[] args){
- //ArrayList代理,通過代理計(jì)算每個(gè)方法調(diào)用所需時(shí)間
- List
arrayListProxy = (List )Proxy.newProxyInstance( - ArrayList.class.getClassLoader(), /*定義代理類的類加載器,用于創(chuàng)建代理對(duì)象,不一定必須是ArrayList,也可以是其他的類加載器*/
- ArrayList.class.getInterfaces(), /*代理類要實(shí)現(xiàn)的接口列表*/
- new MyInvocationHandler(new ArrayList
()) /*指派方法調(diào)用的調(diào)用處理程序,這里用了匿名內(nèi)部類*/ - );
- arrayListProxy.add(2);
- arrayListProxy.add(4);
- System.out.println("--------- 迭代 ---------");
- for(int i : arrayListProxy){
- System.out.print(i + "\t");
- }
- }
- }
從上面代碼看來,客戶端知道代理的實(shí)際目標(biāo)對(duì)象,還知道怎么樣去創(chuàng)建這樣一個(gè)代理對(duì)象,如果想把這些信息全部對(duì)客戶端隱藏起來,可以將這些代碼挪到一個(gè)類中,將它們封裝起來:
- package example;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.concurrent.TimeUnit;
- /**
- * -----------------------------------------
- * @描述 TODO
- * @作者 fancy
- * @郵箱 fancydeepin@yeah.net
- * @日期 2012-8-27
- * -----------------------------------------
- */
- public class ProxyUtil {
- public enum ArrayListProxy {
- PROXY;
- private Object target;
- ArrayListProxy(){
- this.target = new ArrayList
- }
- public List getInstance(){
- return (List)Proxy.newProxyInstance(ArrayList.class.getClassLoader(), ArrayList.class.getInterfaces(),
- new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- long beginTime = System.currentTimeMillis();
- TimeUnit.MICROSECONDS.sleep(1);
- Object obj = method.invoke(target, args);
- long endTime = System.currentTimeMillis();
- System.out.println("[" + method.getName() + "] spend " + (endTime - beginTime) + " ms");
- return obj;
- }
- });
- }
- }
- }
客戶端調(diào)用改成:
- package example;
- import java.util.List;
- import example.ProxyUtil.ArrayListProxy;
- /**
- * -----------------------------------------
- * @描述 TODO
- * @作者 fancy
- * @郵箱 fancydeepin@yeah.net
- * @日期 2012-8-27
- * -----------------------------------------
- */
- public class ProxyApp {
- public static void main(String[] args){
- List
arrayListProxy = ArrayListProxy.PROXY.getInstance(); - arrayListProxy.add(2);
- arrayListProxy.add(4);
- System.out.println("--------- 迭代 ---------");
- for(int i : arrayListProxy){
- System.out.print(i + "\t");
- }
- }
- }
上面代碼中用到了枚舉 enum,如果不想用枚舉,就改用普通類來實(shí)現(xiàn)就行了。
原文鏈接:http://www.blogjava.net/fancydeepin/archive/2012/08/27/java_proxy.html
【編輯推薦】
- 近期面試經(jīng)歷總結(jié)及公司評(píng)價(jià)(上)
- 函數(shù)式編程是一個(gè)倒退
- 為什么Java程序占用的內(nèi)存比實(shí)際分配的多
- Java 8 Lambda:模擬Mixin實(shí)現(xiàn)類多重繼承
- Java項(xiàng)目經(jīng)驗(yàn)——程序員成長的關(guān)鍵
分享名稱:Java動(dòng)態(tài)代理(Proxy)
瀏覽地址:http://www.dlmjj.cn/article/dpsjdgs.html


咨詢
建站咨詢
