一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - Java JDK動(dòng)態(tài)代理(AOP)的實(shí)現(xiàn)原理與使用詳析

Java JDK動(dòng)態(tài)代理(AOP)的實(shí)現(xiàn)原理與使用詳析

2020-12-03 09:59衣舞晨風(fēng) Java教程

所謂代理,就是一個(gè)人或者一個(gè)機(jī)構(gòu)代表另一個(gè)人或者另一個(gè)機(jī)構(gòu)采取行動(dòng)。下面這篇文章主要給大家介紹了關(guān)于Java JDK動(dòng)態(tài)代理(AOP)實(shí)現(xiàn)原理與使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下

本文主要給大家介紹了關(guān)于java jdk動(dòng)態(tài)代理(aop)實(shí)現(xiàn)原理與使用的相關(guān)內(nèi)容,分享出來供大家參考學(xué)習(xí),下面來一起看看詳細(xì)的介紹:

一、什么是代理?

代理是一種常用的設(shè)計(jì)模式,其目的就是為其他對(duì)象提供一個(gè)代理以控制對(duì)某個(gè)對(duì)象的訪問。代理類負(fù)責(zé)為委托類預(yù)處理消息,過濾消息并轉(zhuǎn)發(fā)消息,以及進(jìn)行消息被委托類執(zhí)行后的后續(xù)處理。

代理模式uml圖:

Java JDK動(dòng)態(tài)代理(AOP)的實(shí)現(xiàn)原理與使用詳析

簡單結(jié)構(gòu)示意圖:

Java JDK動(dòng)態(tài)代理(AOP)的實(shí)現(xiàn)原理與使用詳析

為了保持行為的一致性,代理類和委托類通常會(huì)實(shí)現(xiàn)相同的接口,所以在訪問者看來兩者沒有絲毫的區(qū)別。通過代理類這中間一層,能有效控制對(duì)委托類對(duì)象的直接訪問,也可以很好地隱藏和保護(hù)委托類對(duì)象,同時(shí)也為實(shí)施不同控制策略預(yù)留了空間,從而在設(shè)計(jì)上獲得了更大的靈活性。java 動(dòng)態(tài)代理機(jī)制以巧妙的方式近乎完美地實(shí)踐了代理模式的設(shè)計(jì)理念。

二、java 動(dòng)態(tài)代理類

java動(dòng)態(tài)代理類位于java.lang.reflect包下,一般主要涉及到以下兩個(gè)類:

(1)interface invocationhandler:該接口中僅定義了一個(gè)方法

?
1
publicobject invoke(object obj,method method, object[] args)

在實(shí)際使用時(shí),第一個(gè)參數(shù)obj一般是指代理類,method是被代理的方法,如上例中的request(),args為該方法的參數(shù)數(shù)組。這個(gè)抽象方法在代理類中動(dòng)態(tài)實(shí)現(xiàn)。

(2)proxy:該類即為動(dòng)態(tài)代理類,其中主要包含以下內(nèi)容:

protected proxy(invocationhandler h) :構(gòu)造函數(shù),用于給內(nèi)部的h賦值。

static class getproxyclass (classloaderloader, class[] interfaces) :獲得一個(gè)代理類,其中l(wèi)oader是類裝載器,interfaces是真實(shí)類所擁有的全部接口的數(shù)組。

static object newproxyinstance(classloaderloader, class[] interfaces, invocationhandler h) :返回代理類的一個(gè)實(shí)例,返回后的代理類可以當(dāng)作被代理類使用(可使用被代理類的在subject接口中聲明過的方法)

所謂dynamicproxy是這樣一種class:它是在運(yùn)行時(shí)生成的class,在生成它時(shí)你必須提供一組interface給它,然后該class就宣稱它實(shí)現(xiàn)了這些 interface。你當(dāng)然可以把該class的實(shí)例當(dāng)作這些interface中的任何一個(gè)來用。當(dāng)然,這個(gè)dynamicproxy其實(shí)就是一個(gè)proxy,它不會(huì)替你作實(shí)質(zhì)性的工作,在生成它的實(shí)例時(shí)你必須提供一個(gè)handler,由它接管實(shí)際的工作。

在使用動(dòng)態(tài)代理類時(shí),我們必須實(shí)現(xiàn)invocationhandler接口

通過這種方式,被代理的對(duì)象(realsubject)可以在運(yùn)行時(shí)動(dòng)態(tài)改變,需要控制的接口(subject接口)可以在運(yùn)行時(shí)改變,控制的方式(dynamicsubject類)也可以動(dòng)態(tài)改變,從而實(shí)現(xiàn)了非常靈活的動(dòng)態(tài)代理關(guān)系。

動(dòng)態(tài)代理步驟:

       1.創(chuàng)建一個(gè)實(shí)現(xiàn)接口invocationhandler的類,它必須實(shí)現(xiàn)invoke方法

       2.創(chuàng)建被代理的類以及接口

       3.通過proxy的靜態(tài)方法

           newproxyinstance(classloaderloader, class[] interfaces, invocationhandler h)創(chuàng)建一個(gè)代理

       4.通過代理調(diào)用方法

三、jdk的動(dòng)態(tài)代理怎么使用?

1、需要?jiǎng)討B(tài)代理的接口:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package jiankunking;
 
/**
 * 需要?jiǎng)討B(tài)代理的接口
 */
public interface subject
{
 /**
 * 你好
 *
 * @param name
 * @return
 */
 public string sayhello(string name);
 
 /**
 * 再見
 *
 * @return
 */
 public string saygoodbye();
}

2、需要代理的實(shí)際對(duì)象

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package jiankunking;
 
/**
 * 實(shí)際對(duì)象
 */
public class realsubject implements subject
{
 
 /**
 * 你好
 *
 * @param name
 * @return
 */
 public string sayhello(string name)
 {
 return "hello " + name;
 }
 
 /**
 * 再見
 *
 * @return
 */
 public string saygoodbye()
 {
 return " good bye ";
 }
}

3、調(diào)用處理器實(shí)現(xiàn)類(有木有感覺這里就是傳說中的aop啊)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package jiankunking;
 
import java.lang.reflect.invocationhandler;
import java.lang.reflect.method;
 
 
/**
 * 調(diào)用處理器實(shí)現(xiàn)類
 * 每次生成動(dòng)態(tài)代理類對(duì)象時(shí)都需要指定一個(gè)實(shí)現(xiàn)了該接口的調(diào)用處理器對(duì)象
 */
public class invocationhandlerimpl implements invocationhandler
{
 
 /**
 * 這個(gè)就是我們要代理的真實(shí)對(duì)象
 */
 private object subject;
 
 /**
 * 構(gòu)造方法,給我們要代理的真實(shí)對(duì)象賦初值
 *
 * @param subject
 */
 public invocationhandlerimpl(object subject)
 {
 this.subject = subject;
 }
 
 /**
 * 該方法負(fù)責(zé)集中處理動(dòng)態(tài)代理類上的所有方法調(diào)用。
 * 調(diào)用處理器根據(jù)這三個(gè)參數(shù)進(jìn)行預(yù)處理或分派到委托類實(shí)例上反射執(zhí)行
 *
 * @param proxy 代理類實(shí)例
 * @param method 被調(diào)用的方法對(duì)象
 * @param args 調(diào)用參數(shù)
 * @return
 * @throws throwable
 */
 public object invoke(object proxy, method method, object[] args) throws throwable
 {
 //在代理真實(shí)對(duì)象前我們可以添加一些自己的操作
 system.out.println("在調(diào)用之前,我要干點(diǎn)啥呢?");
 
 system.out.println("method:" + method);
 
 //當(dāng)代理對(duì)象調(diào)用真實(shí)對(duì)象的方法時(shí),其會(huì)自動(dòng)的跳轉(zhuǎn)到代理對(duì)象關(guān)聯(lián)的handler對(duì)象的invoke方法來進(jìn)行調(diào)用
 object returnvalue = method.invoke(subject, args);
 
 //在代理真實(shí)對(duì)象后我們也可以添加一些自己的操作
 system.out.println("在調(diào)用之后,我要干點(diǎn)啥呢?");
 
 return returnvalue;
 }
}

4、測試

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package jiankunking;
 
import java.lang.reflect.invocationhandler;
import java.lang.reflect.proxy;
 
/**
 * 動(dòng)態(tài)代理演示
 */
public class dynamicproxydemonstration
{
 public static void main(string[] args)
 {
 //代理的真實(shí)對(duì)象
 subject realsubject = new realsubject();
 
 /**
 * invocationhandlerimpl 實(shí)現(xiàn)了 invocationhandler 接口,并能實(shí)現(xiàn)方法調(diào)用從代理類到委托類的分派轉(zhuǎn)發(fā)
 * 其內(nèi)部通常包含指向委托類實(shí)例的引用,用于真正執(zhí)行分派轉(zhuǎn)發(fā)過來的方法調(diào)用.
 * 即:要代理哪個(gè)真實(shí)對(duì)象,就將該對(duì)象傳進(jìn)去,最后是通過該真實(shí)對(duì)象來調(diào)用其方法
 */
 invocationhandler handler = new invocationhandlerimpl(realsubject);
 
 classloader loader = realsubject.getclass().getclassloader();
 class[] interfaces = realsubject.getclass().getinterfaces();
 /**
 * 該方法用于為指定類裝載器、一組接口及調(diào)用處理器生成動(dòng)態(tài)代理類實(shí)例
 */
 subject subject = (subject) proxy.newproxyinstance(loader, interfaces, handler);
 
 system.out.println("動(dòng)態(tài)代理對(duì)象的類型:"+subject.getclass().getname());
 
 string hello = subject.sayhello("jiankunking");
 system.out.println(hello);
// string goodbye = subject.saygoodbye();
// system.out.println(goodbye);
 }
 
}

5、輸出結(jié)果如下:

演示demo下載地址:dynamicproxydemo.rar

四、動(dòng)態(tài)代理怎么實(shí)現(xiàn)的?

從使用代碼中可以看出,關(guān)鍵點(diǎn)在:

?
1
subject subject = (subject) proxy.newproxyinstance(loader, interfaces, handler);

通過跟蹤提示代碼可以看出:當(dāng)代理對(duì)象調(diào)用真實(shí)對(duì)象的方法時(shí),其會(huì)自動(dòng)的跳轉(zhuǎn)到代理對(duì)象關(guān)聯(lián)的handler對(duì)象的invoke方法來進(jìn)行調(diào)用。

也就是說,當(dāng)代碼執(zhí)行到:

subject.sayhello("jiankunking")這句話時(shí),會(huì)自動(dòng)調(diào)用invocationhandlerimpl的invoke方法。這是為啥呢?

=======橫線之間的是代碼跟分析的過程,不想看的朋友可以直接看結(jié)論============

以下代碼來自:jdk1.8.0_92

既然生成代理對(duì)象是用的proxy類的靜態(tài)方newproxyinstance,那么我們就去它的源碼里看一下它到底都做了些什么?

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/**
 * returns an instance of a proxy class for the specified interfaces
 * that dispatches method invocations to the specified invocation
 * handler.
 *
 * <p>{@code proxy.newproxyinstance} throws
 * {@code illegalargumentexception} for the same reasons that
 * {@code proxy.getproxyclass} does.
 *
 * @param loader the class loader to define the proxy class
 * @param interfaces the list of interfaces for the proxy class
 * to implement
 * @param h the invocation handler to dispatch method invocations to
 * @return a proxy instance with the specified invocation handler of a
 * proxy class that is defined by the specified class loader
 * and that implements the specified interfaces
 * @throws illegalargumentexception if any of the restrictions on the
 * parameters that may be passed to {@code getproxyclass}
 * are violated
 * @throws securityexception if a security manager, <em>s</em>, is present
 * and any of the following conditions is met:
 * <ul>
 * <li> the given {@code loader} is {@code null} and
 * the caller's class loader is not {@code null} and the
 * invocation of {@link securitymanager#checkpermission
 * s.checkpermission} with
 * {@code runtimepermission("getclassloader")} permission
 * denies access;</li>
 * <li> for each proxy interface, {@code intf},
 * the caller's class loader is not the same as or an
 * ancestor of the class loader for {@code intf} and
 * invocation of {@link securitymanager#checkpackageaccess
 * s.checkpackageaccess()} denies access to {@code intf};</li>
 * <li> any of the given proxy interfaces is non-public and the
 * caller class is not in the same {@linkplain package runtime package}
 * as the non-public interface and the invocation of
 * {@link securitymanager#checkpermission s.checkpermission} with
 * {@code reflectpermission("newproxyinpackage.{package name}")}
 * permission denies access.</li>
 * </ul>
 * @throws nullpointerexception if the {@code interfaces} array
 * argument or any of its elements are {@code null}, or
 * if the invocation handler, {@code h}, is
 * {@code null}
 */
@callersensitive
public static object newproxyinstance(classloader loader,
   class<?>[] interfaces,
   invocationhandler h)
 throws illegalargumentexception
 {
 //檢查h 不為空,否則拋異常
 objects.requirenonnull(h);
 
 final class<?>[] intfs = interfaces.clone();
 final securitymanager sm = system.getsecuritymanager();
 if (sm != null) {
 checkproxyaccess(reflection.getcallerclass(), loader, intfs);
 }
 
 /*
 * 獲得與指定類裝載器和一組接口相關(guān)的代理類類型對(duì)象
 */
 class<?> cl = getproxyclass0(loader, intfs);
 
 /*
 * 通過反射獲取構(gòu)造函數(shù)對(duì)象并生成代理類實(shí)例
 */
 try {
 if (sm != null) {
 checknewproxypermission(reflection.getcallerclass(), cl);
 }
 //獲取代理對(duì)象的構(gòu)造方法(也就是$proxy0(invocationhandler h))
 final constructor<?> cons = cl.getconstructor(constructorparams);
 final invocationhandler ih = h;
 if (!modifier.ispublic(cl.getmodifiers())) {
 accesscontroller.doprivileged(new privilegedaction<void>() {
  public void run() {
  cons.setaccessible(true);
  return null;
  }
 });
 }
 //生成代理類的實(shí)例并把invocationhandlerimpl的實(shí)例傳給它的構(gòu)造方法
 return cons.newinstance(new object[]{h});
 } catch (illegalaccessexception|instantiationexception e) {
 throw new internalerror(e.tostring(), e);
 } catch (invocationtargetexception e) {
 throwable t = e.getcause();
 if (t instanceof runtimeexception) {
 throw (runtimeexception) t;
 } else {
 throw new internalerror(t.tostring(), t);
 }
 } catch (nosuchmethodexception e) {
 throw new internalerror(e.tostring(), e);
 }
 }

我們?cè)龠M(jìn)去getproxyclass0方法看一下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
 * generate a proxy class. must call the checkproxyaccess method
 * to perform permission checks before calling this.
 */
 private static class<?> getproxyclass0(classloader loader,
   class<?>... interfaces) {
 if (interfaces.length > 65535) {
 throw new illegalargumentexception("interface limit exceeded");
 }
 
 // if the proxy class defined by the given loader implementing
 // the given interfaces exists, this will simply return the cached copy;
 // otherwise, it will create the proxy class via the proxyclassfactory
 return proxyclasscache.get(loader, interfaces);
 }

 真相還是沒有來到,繼續(xù),看一下proxyclasscache

?
1
2
3
4
5
/**
 * a cache of proxy classes
 */
 private static final weakcache<classloader, class<?>[], class<?>>
 proxyclasscache = new weakcache<>(new keyfactory(), new proxyclassfactory());

奧,原來用了一下緩存啊

那么它對(duì)應(yīng)的get方法啥樣呢?

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/**
 * look-up the value through the cache. this always evaluates the
 * {@code subkeyfactory} function and optionally evaluates
 * {@code valuefactory} function if there is no entry in the cache for given
 * pair of (key, subkey) or the entry has already been cleared.
 *
 * @param key possibly null key
 * @param parameter parameter used together with key to create sub-key and
 *  value (should not be null)
 * @return the cached value (never null)
 * @throws nullpointerexception if {@code parameter} passed in or
 *  {@code sub-key} calculated by
 *  {@code subkeyfactory} or {@code value}
 *  calculated by {@code valuefactory} is null.
 */
 public v get(k key, p parameter) {
 objects.requirenonnull(parameter);
 
 expungestaleentries();
 
 object cachekey = cachekey.valueof(key, refqueue);
 
 // lazily install the 2nd level valuesmap for the particular cachekey
 concurrentmap<object, supplier<v>> valuesmap = map.get(cachekey);
 if (valuesmap == null) {
 //putifabsent這個(gè)方法在key不存在的時(shí)候加入一個(gè)值,如果key存在就不放入
 concurrentmap<object, supplier<v>> oldvaluesmap
 = map.putifabsent(cachekey,
   valuesmap = new concurrenthashmap<>());
 if (oldvaluesmap != null) {
 valuesmap = oldvaluesmap;
 }
 }
 
 // create subkey and retrieve the possible supplier<v> stored by that
 // subkey from valuesmap
 object subkey = objects.requirenonnull(subkeyfactory.apply(key, parameter));
 supplier<v> supplier = valuesmap.get(subkey);
 factory factory = null;
 
 while (true) {
 if (supplier != null) {
 // supplier might be a factory or a cachevalue<v> instance
 v value = supplier.get();
 if (value != null) {
  return value;
 }
 }
 // else no supplier in cache
 // or a supplier that returned null (could be a cleared cachevalue
 // or a factory that wasn't successful in installing the cachevalue)
 
 // lazily construct a factory
 if (factory == null) {
 factory = new factory(key, parameter, subkey, valuesmap);
 }
 
 if (supplier == null) {
 supplier = valuesmap.putifabsent(subkey, factory);
 if (supplier == null) {
  // successfully installed factory
  supplier = factory;
 }
 // else retry with winning supplier
 } else {
 if (valuesmap.replace(subkey, supplier, factory)) {
  // successfully replaced
  // cleared cacheentry / unsuccessful factory
  // with our factory
  supplier = factory;
 } else {
  // retry with current supplier
  supplier = valuesmap.get(subkey);
 }
 }
 }
 }

我們可以看到它調(diào)用了 supplier.get(); 獲取動(dòng)態(tài)代理類,其中supplier是factory,這個(gè)類定義在weakcach的內(nèi)部。

來瞅瞅,get里面又做了什么?

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public synchronized v get() { // serialize access
 // re-check
 supplier<v> supplier = valuesmap.get(subkey);
 if (supplier != this) {
 // something changed while we were waiting:
 // might be that we were replaced by a cachevalue
 // or were removed because of failure ->
 // return null to signal weakcache.get() to retry
 // the loop
 return null;
 }
 // else still us (supplier == this)
 
 // create new value
 v value = null;
 try {
 value = objects.requirenonnull(valuefactory.apply(key, parameter));
 } finally {
 if (value == null) { // remove us on failure
  valuesmap.remove(subkey, this);
 }
 }
 // the only path to reach here is with non-null value
 assert value != null;
 
 // wrap value with cachevalue (weakreference)
 cachevalue<v> cachevalue = new cachevalue<>(value);
 
 // try replacing us with cachevalue (this should always succeed)
 if (valuesmap.replace(subkey, this, cachevalue)) {
 // put also in reversemap
 reversemap.put(cachevalue, boolean.true);
 } else {
 throw new assertionerror("should not reach here");
 }
 
 // successfully replaced us with new cachevalue -> return the value
 // wrapped by it
 return value;
 }
 }

發(fā)現(xiàn)重點(diǎn)還是木有出現(xiàn),但我們可以看到它調(diào)用了valuefactory.apply(key, parameter)方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/**
 * a factory function that generates, defines and returns the proxy class given
 * the classloader and array of interfaces.
 */
 private static final class proxyclassfactory
 implements bifunction<classloader, class<?>[], class<?>>
 {
 // prefix for all proxy class names
 private static final string proxyclassnameprefix = "$proxy";
 
 // next number to use for generation of unique proxy class names
 private static final atomiclong nextuniquenumber = new atomiclong();
 
 @override
 public class<?> apply(classloader loader, class<?>[] interfaces) {
 
 map<class<?>, boolean> interfaceset = new identityhashmap<>(interfaces.length);
 for (class<?> intf : interfaces) {
 /*
 * verify that the class loader resolves the name of this
 * interface to the same class object.
 */
 class<?> interfaceclass = null;
 try {
  interfaceclass = class.forname(intf.getname(), false, loader);
 } catch (classnotfoundexception e) {
 }
 if (interfaceclass != intf) {
  throw new illegalargumentexception(
  intf + " is not visible from class loader");
 }
 /*
 * verify that the class object actually represents an
 * interface.
 */
 if (!interfaceclass.isinterface()) {
  throw new illegalargumentexception(
  interfaceclass.getname() + " is not an interface");
 }
 /*
 * verify that this interface is not a duplicate.
 */
 if (interfaceset.put(interfaceclass, boolean.true) != null) {
  throw new illegalargumentexception(
  "repeated interface: " + interfaceclass.getname());
 }
 }
 
 string proxypkg = null; // package to define proxy class in
 int accessflags = modifier.public | modifier.final;
 
 /*
 * record the package of a non-public proxy interface so that the
 * proxy class will be defined in the same package. verify that
 * all non-public proxy interfaces are in the same package.
 */
 for (class<?> intf : interfaces) {
 int flags = intf.getmodifiers();
 if (!modifier.ispublic(flags)) {
  accessflags = modifier.final;
  string name = intf.getname();
  int n = name.lastindexof('.');
  string pkg = ((n == -1) ? "" : name.substring(0, n + 1));
  if (proxypkg == null) {
  proxypkg = pkg;
  } else if (!pkg.equals(proxypkg)) {
  throw new illegalargumentexception(
  "non-public interfaces from different packages");
  }
 }
 }
 
 if (proxypkg == null) {
 // if no non-public proxy interfaces, use com.sun.proxy package
 proxypkg = reflectutil.proxy_package + ".";
 }
 
 /*
 * choose a name for the proxy class to generate.
 */
 long num = nextuniquenumber.getandincrement();
 string proxyname = proxypkg + proxyclassnameprefix + num;
 
 /*
 * generate the specified proxy class.
 */
 byte[] proxyclassfile = proxygenerator.generateproxyclass(
 proxyname, interfaces, accessflags);
 try {
 return defineclass0(loader, proxyname,
   proxyclassfile, 0, proxyclassfile.length);
 } catch (classformaterror e) {
 /*
 * a classformaterror here means that (barring bugs in the
 * proxy class generation code) there was some other
 * invalid aspect of the arguments supplied to the proxy
 * class creation (such as virtual machine limitations
 * exceeded).
 */
 throw new illegalargumentexception(e.tostring());
 }
 }
 }

通過看代碼終于找到了重點(diǎn):

?
1
2
//生成字節(jié)碼
byte[] proxyclassfile = proxygenerator.generateproxyclass(proxyname, interfaces, accessflags);

那么接下來我們也使用測試一下,使用這個(gè)方法生成的字節(jié)碼是個(gè)什么樣子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package jiankunking;
 
import sun.misc.proxygenerator;
 
import java.io.file;
import java.io.filenotfoundexception;
import java.io.fileoutputstream;
import java.io.ioexception;
import java.lang.reflect.invocationhandler;
import java.lang.reflect.proxy;
 
/**
 * 動(dòng)態(tài)代理演示
 */
public class dynamicproxydemonstration
{
 public static void main(string[] args)
 {
 //代理的真實(shí)對(duì)象
 subject realsubject = new realsubject();
 
 /**
 * invocationhandlerimpl 實(shí)現(xiàn)了 invocationhandler 接口,并能實(shí)現(xiàn)方法調(diào)用從代理類到委托類的分派轉(zhuǎn)發(fā)
 * 其內(nèi)部通常包含指向委托類實(shí)例的引用,用于真正執(zhí)行分派轉(zhuǎn)發(fā)過來的方法調(diào)用.
 * 即:要代理哪個(gè)真實(shí)對(duì)象,就將該對(duì)象傳進(jìn)去,最后是通過該真實(shí)對(duì)象來調(diào)用其方法
 */
 invocationhandler handler = new invocationhandlerimpl(realsubject);
 
 classloader loader = handler.getclass().getclassloader();
 class[] interfaces = realsubject.getclass().getinterfaces();
 /**
 * 該方法用于為指定類裝載器、一組接口及調(diào)用處理器生成動(dòng)態(tài)代理類實(shí)例
 */
 subject subject = (subject) proxy.newproxyinstance(loader, interfaces, handler);
 
 system.out.println("動(dòng)態(tài)代理對(duì)象的類型:"+subject.getclass().getname());
 
 string hello = subject.sayhello("jiankunking");
 system.out.println(hello);
 // 將生成的字節(jié)碼保存到本地,
 createproxyclassfile();
 }
 private static void createproxyclassfile(){
 string name = "proxysubject";
 byte[] data = proxygenerator.generateproxyclass(name,new class[]{subject.class});
 fileoutputstream out =null;
 try {
 out = new fileoutputstream(name+".class");
 system.out.println((new file("hello")).getabsolutepath());
 out.write(data);
 } catch (filenotfoundexception e) {
 e.printstacktrace();
 } catch (ioexception e) {
 e.printstacktrace();
 }finally {
 if(null!=out) try {
 out.close();
 } catch (ioexception e) {
 e.printstacktrace();
 }
 }
 }
 
}

可以看一下這里代理對(duì)象的類型:

Java JDK動(dòng)態(tài)代理(AOP)的實(shí)現(xiàn)原理與使用詳析

我們用jd-jui 工具將生成的字節(jié)碼反編譯:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import java.lang.reflect.invocationhandler;
import java.lang.reflect.method;
import java.lang.reflect.proxy;
import java.lang.reflect.undeclaredthrowableexception;
import jiankunking.subject;
 
public final class proxysubject
 extends proxy
 implements subject
{
 private static method m1;
 private static method m3;
 private static method m4;
 private static method m2;
 private static method m0;
 
 public proxysubject(invocationhandler paraminvocationhandler)
 {
 super(paraminvocationhandler);
 }
 
 public final boolean equals(object paramobject)
 {
 try
 {
 return ((boolean)this.h.invoke(this, m1, new object[] { paramobject })).booleanvalue();
 }
 catch (error|runtimeexception localerror)
 {
 throw localerror;
 }
 catch (throwable localthrowable)
 {
 throw new undeclaredthrowableexception(localthrowable);
 }
 }
 
 public final string saygoodbye()
 {
 try
 {
 return (string)this.h.invoke(this, m3, null);
 }
 catch (error|runtimeexception localerror)
 {
 throw localerror;
 }
 catch (throwable localthrowable)
 {
 throw new undeclaredthrowableexception(localthrowable);
 }
 }
 
 public final string sayhello(string paramstring)
 {
 try
 {
 return (string)this.h.invoke(this, m4, new object[] { paramstring });
 }
 catch (error|runtimeexception localerror)
 {
 throw localerror;
 }
 catch (throwable localthrowable)
 {
 throw new undeclaredthrowableexception(localthrowable);
 }
 }
 
 public final string tostring()
 {
 try
 {
 return (string)this.h.invoke(this, m2, null);
 }
 catch (error|runtimeexception localerror)
 {
 throw localerror;
 }
 catch (throwable localthrowable)
 {
 throw new undeclaredthrowableexception(localthrowable);
 }
 }
 
 public final int hashcode()
 {
 try
 {
 return ((integer)this.h.invoke(this, m0, null)).intvalue();
 }
 catch (error|runtimeexception localerror)
 {
 throw localerror;
 }
 catch (throwable localthrowable)
 {
 throw new undeclaredthrowableexception(localthrowable);
 }
 }
 
 static
 {
 try
 {
 m1 = class.forname("java.lang.object").getmethod("equals", new class[] { class.forname("java.lang.object") });
 m3 = class.forname("jiankunking.subject").getmethod("saygoodbye", new class[0]);
 m4 = class.forname("jiankunking.subject").getmethod("sayhello", new class[] { class.forname("java.lang.string") });
 m2 = class.forname("java.lang.object").getmethod("tostring", new class[0]);
 m0 = class.forname("java.lang.object").getmethod("hashcode", new class[0]);
 return;
 }
 catch (nosuchmethodexception localnosuchmethodexception)
 {
 throw new nosuchmethoderror(localnosuchmethodexception.getmessage());
 }
 catch (classnotfoundexception localclassnotfoundexception)
 {
 throw new noclassdeffounderror(localclassnotfoundexception.getmessage());
 }
 }
}

這就是最終真正的代理類,它繼承自proxy并實(shí)現(xiàn)了我們定義的subject接口

也就是說:

?
1
subject subject = (subject) proxy.newproxyinstance(loader, interfaces, handler);

這里的subject實(shí)際是這個(gè)類的一個(gè)實(shí)例,那么我們調(diào)用它的:

?
1
public final string sayhello(string paramstring)

就是調(diào)用我們定義的invocationhandlerimpl的 invoke方法:

Java JDK動(dòng)態(tài)代理(AOP)的實(shí)現(xiàn)原理與使用詳析

=======橫線之間的是代碼跟分析的過程,不想看的朋友可以直接看結(jié)論================

五、結(jié)論

到了這里,終于解答了:

subject.sayhello("jiankunking")這句話時(shí),為什么會(huì)自動(dòng)調(diào)用invocationhandlerimpl的invoke方法?

因?yàn)閖dk生成的最終真正的代理類,它繼承自proxy并實(shí)現(xiàn)了我們定義的subject接口,在實(shí)現(xiàn)subject接口方法的內(nèi)部,通過反射調(diào)用了invocationhandlerimpl的invoke方法。

包含生成本地class文件的demo:

dynamicproxydemo2.rar

通過分析代碼可以看出java 動(dòng)態(tài)代理,具體有如下四步驟:

  • 通過實(shí)現(xiàn) invocationhandler 接口創(chuàng)建自己的調(diào)用處理器;
  • 通過為 proxy 類指定 classloader 對(duì)象和一組 interface 來創(chuàng)建動(dòng)態(tài)代理類;
  • 通過反射機(jī)制獲得動(dòng)態(tài)代理類的構(gòu)造函數(shù),其唯一參數(shù)類型是調(diào)用處理器接口類型;
  • 通過構(gòu)造函數(shù)創(chuàng)建動(dòng)態(tài)代理類實(shí)例,構(gòu)造時(shí)調(diào)用處理器對(duì)象作為參數(shù)被傳入。

本文參考過:

http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/index.html

好了,以上就是這篇文章的全部內(nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對(duì)服務(wù)器之家的支持。

原文鏈接:http://blog.csdn.net/jiankunking/article/details/52143504

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产精品合集一区二区 | 娇妻与公陈峰姚瑶小说在线阅读 | 探花国产 | 2021海角社区最新版 | oneday日本在线观看完整版 | a级免费在线观看 | 精品一区二区三区波多野结衣 | chinese老头和老太交hd | 久久成人精品免费播放 | 日日摸日日碰夜夜爽97纠 | 男人天堂资源网 | 亚洲精品国产一区二区第一页 | 咪咪爱小说 | 免费高清视频日本 | 久久91精品国产91久久户 | 日本人与黑人做爰视频网站 | 日本人成大片在线 | 亚洲色图欧美视频 | 成人午夜剧场 | 边摸边吃奶边做爽视频免费 | 精灵之森高清在线 | 亚洲精品一区二区久久这里 | 女人张开腿让男人桶视频免费大全 | 欧美日韩一区二区三区韩大 | 奇米色7777| 激情五月开心 | 精品久久久久久久久久香蕉 | 俄罗斯毛片免费大全 | 精品一区heyzo在线播放 | 久久久精品国产免费A片胖妇女 | 免费看片黄 | 無码一区中文字幕少妇熟女H | 丝瓜视频在线观看污 | 欧美一区二区三区综合色视频 | 啊好大好粗| 狠狠色狠狠色综合婷婷tag | 调教催眠改造np总攻 | 欧美日韩看看2015永久免费 | 久久精品午夜一区二区福利 | 好湿好紧太硬了我太爽了网站 | 高清视频免费 |