多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國(guó)內(nèi)最全I(xiàn)T社區(qū)平臺(tái) 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁(yè) > php開(kāi)源 > php教程 > Java動(dòng)態(tài)代理

Java動(dòng)態(tài)代理

來(lái)源:程序員人生   發(fā)布時(shí)間:2017-03-10 10:16:53 閱讀次數(shù):10800次

學(xué)習(xí)Java的同學(xué)注意了?。?! 
學(xué)習(xí)進(jìn)程中遇到甚么問(wèn)題或想獲得學(xué)習(xí)資源的話,歡迎加入Java學(xué)習(xí)交換群,群號(hào)碼:183993990  我們1起學(xué)Java!


今天1個(gè)偶然的機(jī)會(huì)我突然想看看JDK的動(dòng)態(tài)代理,由于之前也知道1點(diǎn),而且只是簡(jiǎn)單的想測(cè)試1下使用,使用很快里就寫好了這么幾個(gè)接口和類:

接口類:UserService.java

復(fù)制代碼
1 package com.yixi.proxy;
2 
3 public interface UserService {
4 
5     public int save() ;
6     
7     public void update(int id);
8     
9 }
復(fù)制代碼

實(shí)現(xiàn)類:UserServiceImpl.java

復(fù)制代碼
 1 package com.yixi.proxy;
 2 
 3 public class UserServiceImpl implements UserService {
 4 
 5     @Override
 6     public int save() {
 7         System.out.println("user save....");
 8         return 1;
 9     }
10 
11     @Override
12     public void update(int id) {
13         System.out.println("update a user " + id);
14     }
15 
16 }
復(fù)制代碼

然后猴急猴急的就寫好了自己要的InvocationHandler:這個(gè)的功能是很簡(jiǎn)單的就是記錄1下方法履行的開(kāi)始時(shí)間和結(jié)束時(shí)間

TimeInvocationHandler.java

復(fù)制代碼
 1 package com.yixi.proxy;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 
 6 public class TimeInvocationHandler implements InvocationHandler {
 7     
 8     @Override
 9     public Object invoke(Object proxy, Method method, Object[] args)
10             throws Throwable {
11         System.out.println("startTime : " +System.currentTimeMillis());
12         Object obj = method.invoke(proxy, args);
13         System.out.println("endTime : " +System.currentTimeMillis());
14         return obj;
15     }
16 
17 }
復(fù)制代碼

所有的準(zhǔn)備工作都弄好了 固然要開(kāi)始寫測(cè)試了!

Test.java

復(fù)制代碼
 1  package com.yixi.proxy;
 2  import java.lang.reflect.Proxy;
 3   
 4   public class Test {
 5   
 6      public static void main(String[] args) { 
 7          TimeInvocationHandler timeHandler = new TimeInvocationHandler();
 8          UserService u =  (UserService) Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), timeHandler);
 9          u.update(2);
10          u.save();
11      }
12  }
復(fù)制代碼

 

愉快地Run了1下,不過(guò)它其實(shí)不給你面子 結(jié)果是滿屏幕的異常:

復(fù)制代碼
 1 startTime : 1352877835040
 2 startTime : 1352877835040
 3 startTime : 1352877835040
 4 Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
 5     at $Proxy0.update(Unknown Source)
 6     at com.yixi.proxy.Test.main(Test.java:11)
 7 Caused by: java.lang.reflect.InvocationTargetException
 8     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 9     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
10     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
11     at java.lang.reflect.Method.invoke(Method.java:597)
12     at com.yixi.proxy.TimeInvocationHandler.invoke(TimeInvocationHandler.java:12)
13     ... 2 more

復(fù)制代碼
com.yixi.proxy.TimeInvocationHandler.invoke(TimeInvocationHandler.java:12)

異常明確告知了是在TimeInvocationHandle的12行的問(wèn)題:也就是

復(fù)制代碼
1 public Object invoke(Object proxy, Method method, Object[] args)
2             throws Throwable {
3         System.out.println("startTime : " +System.currentTimeMillis());
4         Object obj = method.invoke(proxy, args);
5         System.out.println("endTime : " +System.currentTimeMillis());
6         return obj;
7     }
復(fù)制代碼

從方法上來(lái)看沒(méi)甚么毛病??!由于在invoke()這個(gè)方法上貌似提供了method.invoke(Object,Object[])所要的所有的參數(shù),我們會(huì)理所應(yīng)當(dāng)?shù)娜ナ褂盟?,如果你真那樣想的?那你就中了JDK的圈套了,先看下正確的寫法吧 避免有些同學(xué)沒(méi)心情看后面的 最少給個(gè)正確的解法:

修改TimeInvocationHandler.java

復(fù)制代碼
 1 package com.yixi.proxy;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 
 6 public class TimeInvocationHandler implements InvocationHandler {
 7     
 8     private Object o;
 9     
10     public TimeInvocationHandler(Object o){
11         this.o = o;
12     }
13     
14     @Override
15     public Object invoke(Object proxy, Method method, Object[] args)
16             throws Throwable {
17         System.out.println("startTime : " +System.currentTimeMillis());
18         Object obj = method.invoke(o, args);
19         System.out.println("endTime : " +System.currentTimeMillis());
20         return obj;
21     }
22 
23 }
復(fù)制代碼

修改Test.java

復(fù)制代碼
 1 package com.yixi.proxy;
 2 
 3 import java.lang.reflect.Proxy;
 4 
 5 public class Test {
 6 
 7     public static void main(String[] args) {
 8         TimeInvocationHandler timeHandler = new TimeInvocationHandler(new UserServiceImpl());
 9         UserService u =  (UserService) Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), timeHandler);
10         u.update(2);
11         u.save();
12     }
13 }
復(fù)制代碼

現(xiàn)在是正確的輸出結(jié)果:

1 startTime : 1352879531334
2 update a user 2
3 endTime : 1352879531334
4 startTime : 1352879531334
5 user save....
6 endTime : 1352879531335

如果想代碼少1點(diǎn)的話可以直接寫匿名類:

復(fù)制代碼
 1 package com.yixi.proxy;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 import java.lang.reflect.Proxy;
 6 
 7 public class Test {
 8 
 9     public static void main(String[] args) {
10         final UserServiceImpl usi = new UserServiceImpl();
11         UserService u =  (UserService) Proxy.newProxyInstance(
12                 usi.getClass().getClassLoader(),
13                 usi.getClass().getInterfaces(),
14                 new InvocationHandler() {
15                     
16                     @Override
17                     public Object invoke(Object proxy, Method method, Object[] args)
18                             throws Throwable {
19                         System.out.println("startTime : " +System.currentTimeMillis());
20                         Object obj = method.invoke(usi, args);
21                         System.out.println("endTime : " +System.currentTimeMillis());
22                         return obj;
23                     }
24                 });
25         u.update(2);
26         u.save();
27     }
28 }
復(fù)制代碼

既然method.invoke(target,args);中第1個(gè)參數(shù)是傳入的是目標(biāo)對(duì)象 那末invocationHandler的Invoke方法要個(gè)Object proxy參數(shù)干嗎呢 ? 還是往下看吧!

對(duì)最重要的invoke這個(gè)方法(個(gè)人覺(jué)得)我們看下JDK是怎樣說(shuō)的吧:

復(fù)制代碼
 1 invoke
 2 Object invoke(Object proxy,
 3               Method method,
 4               Object[] args)
 5               throws Throwable在代理實(shí)例上處理方法調(diào)用并返回結(jié)果。在與方法關(guān)聯(lián)的代理實(shí)例上調(diào)用方法時(shí),將在調(diào)用途理程序上調(diào)用此方法。 
 6 
 7 參數(shù):
 8 proxy - 在其上調(diào)用方法的代理實(shí)例
 9 method - 對(duì)應(yīng)于在代理實(shí)例上調(diào)用的接口方法的 Method 實(shí)例。Method 對(duì)象的聲明類將是在其中聲明方法的接口,該接口可以是代理類賴以繼承方法的代理接口的超接口。
10 args - 包括傳入代理實(shí)例上方法調(diào)用的參數(shù)值的對(duì)象數(shù)組,如果接口方法不使用參數(shù),則為 null?;绢愋偷膮?shù)被包裝在適當(dāng)基本包裝器類(如 java.lang.Integer 或 java.lang.Boolean)的實(shí)例中。 
復(fù)制代碼

proxy - 在其上調(diào)用方法的代理實(shí)例 ? 這句話是甚么意思呢? 代理? method是代理的方法? 那我履行代理的method不是就應(yīng)當(dāng)是Object obj = method.invoke(proxy, args);嗎? 當(dāng)時(shí)我也沒(méi)轉(zhuǎn)過(guò)彎來(lái),去討論群,去google都沒(méi)找到甚么靈感,想一想還是這個(gè)看看源碼吧 或許能看到點(diǎn)甚么!

打開(kāi)Proxy類的源碼發(fā)現(xiàn)有這么1個(gè)構(gòu)造方法:

1 protected InvocationHandler h;
2 
3 protected Proxy(InvocationHandler h) {
4     this.h = h;
5     }

把InvocationHandler作為Proxy的構(gòu)造方法的參數(shù)....那它要InvocationHandler干甚么用呢?跟InvocationHandler中的invoke()方法有甚么聯(lián)系嗎?

我第1個(gè)想到的是Proxy內(nèi)部會(huì)調(diào)用下面的語(yǔ)句:

1 h.invoke(this,this.getClass().getMethod(methodName),args);

由于總得去調(diào)用invoke方法才能履行相應(yīng)的method方法吧,

我們先來(lái)看下這個(gè)

在這里你就會(huì)發(fā)現(xiàn)貌似有點(diǎn)感覺(jué)了:當(dāng)u.update(2)時(shí)  Proxy就會(huì)調(diào)用 handler.invoke(proxyClass,update,2)  也就是調(diào)用了proxyClass.update(2);

當(dāng)u.save();時(shí) Proxy就會(huì)調(diào)用handler.invoke(proxyClass,save,null)  也就是調(diào)用了proxyClass.save();

 所以1開(kāi)始的毛病是對(duì)InvocationHandler的invoke方法的理解的毛??! 全部的invoke()方法

復(fù)制代碼
1                     @Override
2                     public Object invoke(Object proxy, Method method, Object[] args)
3                             throws Throwable {
4                         System.out.println("startTime : " +System.currentTimeMillis());
5                         Object obj = method.invoke(usi, args);
6                         System.out.println("endTime : " +System.currentTimeMillis());
7                         return obj;
8                     }
復(fù)制代碼

其實(shí)就是代理對(duì)象的1個(gè)代理方法,履行代理對(duì)象的1個(gè)方法就會(huì)訪問(wèn)1次invoke()方法;在invoke方法中的Object obj = method.invoke(usi, args); 是按原對(duì)象本應(yīng)當(dāng)履行的方式履行,該返回甚么就返回甚么。不知道你能想到點(diǎn)甚么啵。下面來(lái)驗(yàn)證1下:

當(dāng)Test.java改成這樣時(shí):

復(fù)制代碼
 1 public class Test {
 2 
 3     public static void main(String[] args) {
 4         final UserServiceImpl usi = new UserServiceImpl();
 5         UserService u =  (UserService) Proxy.newProxyInstance(
 6                 usi.getClass().getClassLoader(),
 7                 usi.getClass().getInterfaces(),
 8                 new InvocationHandler() {
 9                     
10                     @Override
11                     public Object invoke(Object proxy, Method method, Object[] args)
12                             throws Throwable {
13                         return null;
14                     }
15                 });
16         u.update(2);
17         u.save();
18     }
19 }
復(fù)制代碼

注意這時(shí)候候的匿名類的方法的返回的是null,運(yùn)行1下就會(huì)發(fā)現(xiàn):

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

17行有空指針 也就是這里的u.save()方法有為null的元素 難道是u是空的? 不應(yīng)當(dāng)啊如果u是null的話那末u.update(2)在那里就會(huì)報(bào)空指針異常了,當(dāng)我把17行注釋掉以后異常沒(méi)了說(shuō)明u.update()能正常履行。那這究竟是為何呢?

其實(shí)這就是invoke方法返回null的原因:

注意1下UserService類中的兩個(gè)方法:

復(fù)制代碼
1 public interface UserService {
2 
3     public int save() ;
4     
5     public void update(int id);
6     
7 }
復(fù)制代碼

Save()方法返回的是int型的 而update方法返回的是void型的;根據(jù)上面的猜想是 handler.invoke()是實(shí)現(xiàn) proxyClass.update(2);的,invoke方法中的return方法的是相應(yīng)的代理方法的返回值,

所以在invoke方法返回null的時(shí)候代理的update方法接收到返回值是null, 而它本來(lái)就是返回void 所以沒(méi)有報(bào)異常, 而代理save必須返回int型的數(shù)值 我們這返回的還是null,JVM沒(méi)法將null轉(zhuǎn)化為int型 所以就報(bào)了異常了

這樣解釋就可以解釋通了,也能相對(duì)證明前面的猜想。

InvocationHandler中invoke方法中第1個(gè)參數(shù)proxy貌似只是為了讓Proxy類能給自己的InvocationHandler對(duì)象的援用調(diào)用方法時(shí)能傳入代理對(duì)象proxyClass的援用,來(lái)完成proxyClass需要完成的業(yè)務(wù)。

學(xué)習(xí)Java的同學(xué)注意了!??! 
學(xué)習(xí)進(jìn)程中遇到甚么問(wèn)題或想獲得學(xué)習(xí)資源的話,歡迎加入Java學(xué)習(xí)交換群,群號(hào)碼:183993990  我們1起學(xué)Java!

生活不易,碼農(nóng)辛苦
如果您覺(jué)得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 国内精品免费视频精选在线观看 | 国产香蕉在线精彩视频 | 中文亚洲日韩欧美 | 国产精品爱久久久久久久三级 | 欧美激情视频一区二区三区 | 91在线 一区 二区三区 | 手机看片日韩日韩国产在线看 | 国产在线喷潮免费观看 | 国产二区自拍 | 成人欧美视频在线看免费 | 欧美成人国产一区二区 | 国内精品视频九九九九 | 国产成人久久精品二区三区牛 | 欧美成人毛片一级在线 | 欧美日韩福利视频一区二区三区 | 成人a毛片手机免费播放 | 免费区欧美一级毛片精品 | 一区二区在线看 | 动漫美女羞羞网站 | 最新lutube亚洲看片在线观看 | 免费一区二区三区 | 免费在线观看一级毛片 | 亚洲图片欧美视频 | 亚洲欧美另类日韩 | 中文字幕在线免费观看 | 日本亚洲高清 | 亚洲图片校园另激情类小说 | 亚洲视频在线不卡 | 亚洲综合久久综合激情久久 | 色综合欧美综合天天综合 | 亚洲精品美女久久久aaa | 性欧美18一19sex高清 | 婷婷色一二三区波多野衣 | 日韩久久久精品中文字幕 | 国产xx在线观看 | 国产在线观看成人 | 亚洲天堂久久精品成人 | 日韩性网站| 欧美爱爱爽爽视频在线观看 | 国产精品任我爽爆在线播放66 | 成人精品一区二区三区中文字幕 |