亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

代理模式之Java動態代理實現方法

2019-11-26 16:18:50
字體:
來源:轉載
供稿:網友

今天一個偶然的機會我突然想看看JDK的動態代理,因為以前也知道一點,而且只是簡單的想測試一下使用,使用很快里就寫好了這么幾個接口和類:
接口類:UserService.java

復制代碼 代碼如下:

package com.yixi.proxy;
public interface UserService {
    public int save() ;
    public void update(int id);
}

實現類:UserServiceImpl.java
復制代碼 代碼如下:

package com.yixi.proxy;
public class UserServiceImpl implements UserService {
    @Override
    public int save() {
        System.out.println("user save....");
        return 1;
    }
    @Override
    public void update(int id) {
        System.out.println("update a user " + id);
    }
}

然后猴急猴急的就寫好了自己要的InvocationHandler:這個的功能是很簡單的就是記錄一下方法執行的開始時間和結束時間
TimeInvocationHandler.java
復制代碼 代碼如下:

package com.yixi.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TimeInvocationHandler implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("startTime : " +System.currentTimeMillis());
        Object obj = method.invoke(proxy, args);
        System.out.println("endTime : " +System.currentTimeMillis());
        return obj;
    }
}

所有的準備工作都弄好了 當然要開始寫測試了!
Test.java
復制代碼 代碼如下:

package com.yixi.proxy;
import java.lang.reflect.Proxy;
public class Test {
    public static void main(String[] args) { 9         TimeInvocationHandler timeHandler = new TimeInvocationHandler();
        UserService u =  (UserService) Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), timeHandler);
        u.update(2);
        u.save();
    }
}

愉快地Run了一下,不過它并不給你面子 結果是滿屏幕的異常:
復制代碼 代碼如下:

startTime : 1352877835040
startTime : 1352877835040
startTime : 1352877835040
Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
    at $Proxy0.update(Unknown Source)
    at com.yixi.proxy.Test.main(Test.java:11)
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.yixi.proxy.TimeInvocationHandler.invoke(TimeInvocationHandler.java:12)
    ... 2 more

com.yixi.proxy.TimeInvocationHandler.invoke(TimeInvocationHandler.java:12)異常明確告訴了是在TimeInvocationHandle的12行的問題:也就是
復制代碼 代碼如下:

public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("startTime : " +System.currentTimeMillis());
        Object obj = method.invoke(proxy, args);
        System.out.println("endTime : " +System.currentTimeMillis());
        return obj;
    }

從方法上來看沒什么錯誤??!因為在invoke()這個方法上貌似提供了method.invoke(Object,Object[])所要的所有的參數,我們會理所應當的去使用它,如果你真那樣想的話 那你就中了JDK的陷阱了,先看下正確的寫法吧 防止有些同學沒心情看后面的 至少給個正確的解法:
修改TimeInvocationHandler.java
復制代碼 代碼如下:

package com.yixi.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TimeInvocationHandler implements InvocationHandler {
    private Object o;
    public TimeInvocationHandler(Object o){
        this.o = o;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("startTime : " +System.currentTimeMillis());
        Object obj = method.invoke(o, args);
        System.out.println("endTime : " +System.currentTimeMillis());
        return obj;
    }
}

修改Test.java
復制代碼 代碼如下:

package com.yixi.proxy;
import java.lang.reflect.Proxy;
public class Test {
    public static void main(String[] args) {
        TimeInvocationHandler timeHandler = new TimeInvocationHandler(new UserServiceImpl());
        UserService u =  (UserService) Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), timeHandler);
        u.update(2);
        u.save();
    }
}

現在是正確的輸出結果:
復制代碼 代碼如下:

startTime : 1352879531334
update a user 2
endTime : 1352879531334
startTime : 1352879531334
user save....
endTime : 1352879531335

如果想代碼少一點的話可以直接寫匿名類:
package com.yixi.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Test {
    public static void main(String[] args) {
        final UserServiceImpl usi = new UserServiceImpl();
        UserService u =  (UserService) Proxy.newProxyInstance(
                usi.getClass().getClassLoader(),
                usi.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {
                        System.out.println("startTime : " +System.currentTimeMillis());
                        Object obj = method.invoke(usi, args);
                        System.out.println("endTime : " +System.currentTimeMillis());
                        return obj;
                    }
                });
        u.update(2);
        u.save();
    }
}
既然method.invoke(target,args);中第一個參數是傳入的是目標對象 那么invocationHandler的Invoke方法要個Object proxy參數干嘛呢 ? 還是往下看吧!
對于最重要的invoke這個方法(個人覺得)我們看下JDK是怎么說的吧:
復制代碼 代碼如下:

invoke
Object invoke(Object proxy,
              Method method,
              Object[] args)
              throws Throwable在代理實例上處理方法調用并返回結果。在與方法關聯的代理實例上調用方法時,將在調用處理程序上調用此方法。
參數:
proxy - 在其上調用方法的代理實例
method - 對應于在代理實例上調用的接口方法的 Method 實例。Method 對象的聲明類將是在其中聲明方法的接口,該接口可以是代理類賴以繼承方法的代理接口的超接口。
args - 包含傳入代理實例上方法調用的參數值的對象數組,如果接口方法不使用參數,則為 null。基本類型的參數被包裝在適當基本包裝器類(如 java.lang.Integer 或 java.lang.Boolean)的實例中。

proxy - 在其上調用方法的代理實例 ? 這句話是什么意思呢? 代理? method是代理的方法? 那我執行代理的method不是就應該是Object obj = method.invoke(proxy, args);嗎? 當時我也沒轉過彎來,去討論群,去google都沒找到什么靈感,想想還是這個看看源碼吧 也許能看到點什么!
打開Proxy類的源碼發現有怎么一個構造方法:
復制代碼 代碼如下:

protected InvocationHandler h;

protected Proxy(InvocationHandler h) {
    this.h = h;
    }


把InvocationHandler作為Proxy的構造方法的參數....那它要InvocationHandler干什么用呢?跟InvocationHandler中的invoke()方法有什么聯系嗎?
我第一個想到的是Proxy內部會調用下面的語句:
復制代碼 代碼如下:

h.invoke(this,methodName,args);

因為總得去調用invoke方法才能執行相應的method方法吧,
我們先來看下這個

在這里你就會發現貌似有點感覺了:當u.update(2)時 àProxy就會調用 handler.invoke(proxyClass,update,2) à 也就是調用了proxyClass.update(2);
當u.save();時àProxy就會調用handler.invoke(proxyClass,save,null) à也就是調用了proxyClass.save();

當Test.java改成這樣時:

復制代碼 代碼如下:

public class Test {
    public static void main(String[] args) {
        final UserServiceImpl usi = new UserServiceImpl();
        UserService u =  (UserService) Proxy.newProxyInstance(
                usi.getClass().getClassLoader(),
                usi.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {
                        return null;
                    }
                });
        u.update(2);
        u.save();
    }
}

注意這時候的匿名類的方法的返回的是null,運行一下就會發現:
復制代碼 代碼如下:

Exception in thread "main" java.lang.NullPointerException
    at $Proxy0.save(Unknown Source)
    at com.yixi.proxy.Test.main(Test.java:17)

17行有空指針 也就是這里的u.save()方法有為null的元素 難道是u是空的? 不應該啊如果u是null的話那么u.update(2)在那里就會報空指針異常了,當我把17行注釋掉以后異常沒了說明u.update()能正常執行。那這到底是為什么呢?
其實這就是invoke方法返回null的緣故:
注意一下UserService類中的兩個方法:
復制代碼 代碼如下:

public interface UserService {
    public int save() ;
    public void update(int id);
}

Save()方法返回的是int型的 而update方法返回的是void型的;根據上面的猜測是 handler.invoke()是實現 proxyClass.update(2);的,invoke方法中的return方法的是相應的代理方法的返回值,
所以在invoke方法返回null的時候代理的update方法接收到返回值是null, 而它本來就是返回void 所以沒有報異常, 而代理save必須返回int型的數值 我們這返回的還是null,JVM無法將null轉化為int型 所以就報了異常了
這樣解釋就能解釋通了,也能相對證明前面的猜測。
InvocationHandler中invoke方法中第一個參數proxy貌似只是為了讓Proxy類能給自己的InvocationHandler對象的引用調用方法時能傳入代理對象proxyClass的引用,來完成proxyClass需要完成的業務。

文采不行!能力有限!希望大家指正...

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美夫妻性生活视频| 555www成人网| 在线电影中文日韩| 国产精品黄色影片导航在线观看| 国内精久久久久久久久久人| 亚洲男子天堂网| 91国产美女在线观看| 国产精品永久在线| 亚洲一区二区中文字幕| 国产精品吊钟奶在线| 国产suv精品一区二区| 日韩高清中文字幕| 91精品综合久久久久久五月天| 日韩精品电影网| 亚洲天堂2020| 久久福利网址导航| 91精品国产综合久久男男| 亚洲男人天堂视频| 91色视频在线导航| 国产99久久久欧美黑人| 中文字幕亚洲综合久久| 久久在线精品视频| 欧美专区在线播放| 大桥未久av一区二区三区| 在线观看日韩www视频免费| 伊人伊成久久人综合网站| 91精品久久久久久久| 亚洲欧美日韩在线高清直播| 亚洲影院在线看| 亚洲白拍色综合图区| 日本一区二三区好的精华液| 日韩av在线不卡| 亚洲男人天堂视频| 国产成人一区二区三区| 91精品在线观看视频| 最近2019中文字幕第三页视频| 国产精品免费一区豆花| 欧美一区三区三区高中清蜜桃| 国产精品网站入口| 色偷偷偷亚洲综合网另类| 国产偷国产偷亚洲清高网站| 欧美日韩精品中文字幕| 国产精品福利久久久| 欧美巨乳在线观看| 国产精品国产三级国产aⅴ浪潮| 亚洲精品视频网上网址在线观看| 亚洲一区二区中文字幕| 成人综合国产精品| 一区二区三区四区在线观看视频| 国产精品h在线观看| 日韩经典第一页| 久久久av电影| 久久久欧美一区二区| 最好看的2019年中文视频| 国产欧美精品日韩精品| 97免费在线视频| 久久视频中文字幕| 成人国产精品免费视频| 97国产精品人人爽人人做| 国产精品激情自拍| 亚洲午夜久久久久久久| 欧美猛交ⅹxxx乱大交视频| 国产精品aaa| 国产va免费精品高清在线| 日韩精品有码在线观看| 久久视频免费在线播放| 性视频1819p久久| 精品福利免费观看| 亚洲国产成人精品久久久国产成人一区| 日韩中文在线中文网三级| 欧美激情国内偷拍| 亚洲欧美激情在线视频| 久久久国产影院| 欧洲一区二区视频| 亚洲精品wwwww| 中文字幕亚洲欧美| 欧美日韩国产丝袜美女| 欧美电影免费观看高清完整| 最近2019年中文视频免费在线观看| 国产精品自产拍在线观| www.日韩av.com| 日韩电影中文字幕一区| 欧美一级大片在线免费观看| 国产精品日韩欧美大师| 国产精品综合不卡av| 欧美日韩国内自拍| 日韩高清有码在线| 国产91网红主播在线观看| 亚洲精品动漫100p| 久久久久北条麻妃免费看| 日韩大片免费观看视频播放| 韩国美女主播一区| 午夜精品久久久99热福利| www.日韩av.com| 久久久久久欧美| 欧美日韩成人黄色| 国产精品视频精品视频| 欧美激情乱人伦一区| 久久久精品视频在线观看| 91日本在线视频| 亚洲人永久免费| 亚洲美女www午夜| 欧美在线日韩在线| 日韩中文字幕网站| 国产精品免费观看在线| 亚洲精品视频网上网址在线观看| 成人久久18免费网站图片| 日韩最新av在线| 国语自产精品视频在线看一大j8| 亚洲www视频| 色在人av网站天堂精品| 亚洲精品一区av在线播放| 亚洲国产欧美在线成人app| 国产成人精品视频| 一本一本久久a久久精品牛牛影视| 91免费看片网站| 亚洲欧美一区二区精品久久久| 欧美午夜宅男影院在线观看| 国产欧美va欧美va香蕉在| 在线视频欧美日韩精品| 亚洲激情视频网站| 97精品一区二区三区| 成人黄色片网站| 国产福利精品在线| 久久久国产成人精品| 揄拍成人国产精品视频| 亚洲成人网在线观看| 欧美视频免费在线| 久久久中文字幕| 欧美日本国产在线| 亚洲二区在线播放视频| 亚洲高清一区二| 日韩男女性生活视频| 一区三区二区视频| 久久天天躁日日躁| 精品亚洲一区二区三区在线观看| 日韩h在线观看| 国产在线观看91精品一区| 狠狠色狠狠色综合日日小说| 欧美精品videosex极品1| 成人精品网站在线观看| 欧美成人一区二区三区电影| 亚洲国产另类久久精品| 精品久久久久久久久久久久久| 在线性视频日韩欧美| 亚洲xxxxx电影| 国产97人人超碰caoprom| 在线不卡国产精品| 国产精品入口免费视| 亚洲欧美激情精品一区二区| 性色av一区二区三区免费| 国产精彩精品视频| 美日韩精品免费观看视频| 久久久久久久国产精品视频| 国产在线观看不卡| 国产精品中文在线| 亚洲视频欧洲视频| 成人久久18免费网站图片| 亚洲欧美日韩在线高清直播| 欧美大尺度电影在线观看| 国产丝袜一区视频在线观看| 国产午夜精品一区理论片飘花| 精品国偷自产在线| 爽爽爽爽爽爽爽成人免费观看|