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

服務(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提高第八篇 動態(tài)代理技術(shù)

JAVA提高第八篇 動態(tài)代理技術(shù)

2021-01-28 12:25pony1223 Java教程

這篇文章主要為大家詳細(xì)介紹了JAVA動態(tài)代理技術(shù)的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下

對于動態(tài)代理,學(xué)過aop的應(yīng)該都不會陌生,因為代理是實現(xiàn)aop功能的核心和關(guān)鍵技術(shù)。那么今天我們將開始動態(tài)代理的學(xué)習(xí):

一、引出動態(tài)代理

生活中代理應(yīng)該是很常見的,比如你可以通過代理商去買電腦,也可以直接找廠商買電腦,最終都是買到了電腦。程序中也一樣存在代理的情況,比如要為已經(jīng)存在的多個具有相同接口的目標(biāo)類的各個方法增加一些系統(tǒng)功能,例如:異常處理、日志、計算方法耗時等等,那么我們會怎么做呢?

1.會編寫一個與目標(biāo)類擁有相同接口的代理類,代理類的每個方法調(diào)用目標(biāo)類的相同方法,然后在調(diào)用方法前后加上系統(tǒng)功能所需要的代碼。

2.如果采用工廠模式或者配置文件的方式進(jìn)行管理,則不需要修改客戶端程序,在配置文件中配置是使用目標(biāo)類、還是代理類,這樣以后很容易切換。

樣例如下:

?
1
2
3
4
5
public class x{
 public void sayhello(){
 syso:say hello;
 }
}

現(xiàn)在我要在這個方法之前添加一個時間,方法之后添加一個時間,計算這個方法執(zhí)行的時間一共是多少.如果我沒有得到sayhello源碼,那么我怎么做呢?寫一個代理:

?
1
2
3
4
5
6
7
8
9
10
public class xproxy
{
 private x x;
 public void sayhello
 {
  starttime:
  x.syhello();
  endtime;
 }
}

說明:上面的是偽代碼。

把開始時間和結(jié)束時間放在這個方法的前后就可以了.
通常我們讓兩個方法實現(xiàn)同一個接口.那么client想用x也可以,想用xproxy也可以了.具體的原理圖,如下圖所示:

JAVA提高第八篇 動態(tài)代理技術(shù)

二、創(chuàng)建動態(tài)代理類

現(xiàn)在試想一下,上面只是代理了一個目標(biāo)類,如果多個目標(biāo)類,那么是不是要創(chuàng)建n多個代理類呢?那樣不是代碼太不靈活且笨重了。當(dāng)然不會。

java虛擬機(jī)可以在運(yùn)行期間動態(tài)生成類,這種類是以字節(jié)碼的形式生成出來的。這種動態(tài)生成的類往往呢就是代理類。即動態(tài)代理類。

jvm生成的動態(tài)代理類必須滿足一定的條件,這就是必須實現(xiàn)一個或多個接口。所以jvm生成的動態(tài)代理只能用作具有相同接口的目標(biāo)類的代理。(動態(tài)生成的類不是代理,我們只是吧這個類當(dāng)成代理來用。)

proxy動態(tài)代理的api:

JAVA提高第八篇 動態(tài)代理技術(shù)

兩個參數(shù)應(yīng)該很容易理解:

第一個參數(shù):我們知道任何一個字節(jié)碼都是需要通過類加載器來加載的,那么這個動態(tài)生成的字節(jié)碼也不例外,需要給它一個類加載器。

第二個參數(shù):就是動態(tài)代理類生成,必須滿足的一個條件,需要實現(xiàn)一個或者多個接口,否則這個生成的類字節(jié)碼中就沒有方法了,沒有方法就失去了其功能意義。

下面我們動手來創(chuàng)建一個動態(tài)的代理類,大體思路為:

1.創(chuàng)建實現(xiàn)collection接口的動態(tài)類和查看其名稱,分析proxy.getproxyclass方法的各個參數(shù)

2.編碼列出動態(tài)類中的所有構(gòu)造方法和參數(shù)簽名

3.編碼列出動態(tài)類中的所有方法和參數(shù)簽名

4.創(chuàng)建動態(tài)類的實例對象:1)用反射獲取構(gòu)造方法   2)編寫一個最簡單的invocationhandle類   3)調(diào)用構(gòu)造方法創(chuàng)建動態(tài)類的實例對象,并將編寫的invocationhandle類的實例對象傳遞進(jìn)去   4)打印創(chuàng)建對象和調(diào)用對象的沒有返回的方法和getclass方法,演示調(diào)用其他有返回值方法報告了異常。

5)將創(chuàng)建動態(tài)類的實例對象的代理寫成匿名內(nèi)部類方式,簡化代碼。

樣例分步實現(xiàn)如下:

(1)首先我們來完成前面3步:

?
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
package study.javaenhance;
 
import java.lang.reflect.constructor;
import java.lang.reflect.method;
import java.lang.reflect.proxy;
import java.util.collection;
 
public class proxytest
{
 public static void main(string[] args)
 {
  class clazzproxy1 = proxy.getproxyclass(collection.class.getclassloader(),collection.class);
  system.out.println(clazzproxy1.getname());
  
  //上面輸出的為一個類,那么一個類肯定有其構(gòu)造方法和方法,下面我們來列出來
  
  system.out.println("----------begin constructors list----------");
  //1.列出構(gòu)造方法
  constructor[] constructors = clazzproxy1.getconstructors();
  for (constructor constructor : constructors)
  {
   string name = constructor.getname();
   stringbuilder sbuilder = new stringbuilder(name);
   sbuilder.append('(');
   class[] clazzparams = constructor.getparametertypes();
   for (class clazzparam : clazzparams) {
    sbuilder.append(clazzparam.getname()).append(',');
   }
   if(clazzparams!=null && clazzparams.length != 0)
    sbuilder.deletecharat(sbuilder.length()-1);
   sbuilder.append(')');
   system.out.println(sbuilder.tostring());
  }
  
  //2.列出這個類字節(jié)碼中的所有方法
  system.out.println("----------begin methods list----------");
  method[] methods = clazzproxy1.getmethods();
  for(method method : methods){
   string name = method.getname();
   stringbuilder sbuilder = new stringbuilder(name);
   sbuilder.append('(');
   class[] clazzparams = method.getparametertypes();
   for(class clazzparam : clazzparams){
    sbuilder.append(clazzparam.getname()).append(',');
   }
   if(clazzparams!=null && clazzparams.length != 0)
    sbuilder.deletecharat(sbuilder.length()-1);
   sbuilder.append(')');
   system.out.println(sbuilder.tostring());  
  }
  
  
 }
 
}

輸出結(jié)果如下:

$proxy0
----------begin constructors list----------
$proxy0(java.lang.reflect.invocationhandler)
----------begin methods list----------
add(java.lang.object)
hashcode()
clear()
equals(java.lang.object)
tostring()
contains(java.lang.object)
isempty()
addall(java.util.collection)
iterator()
size()
toarray([ljava.lang.object;)
toarray()
remove(java.lang.object)
containsall(java.util.collection)
removeall(java.util.collection)
retainall(java.util.collection)
isproxyclass(java.lang.class)
getproxyclass(java.lang.classloader,[ljava.lang.class;)
getinvocationhandler(java.lang.object)
newproxyinstance(java.lang.classloader,[ljava.lang.class;,java.lang.reflect.invocationhandler)
wait()
wait(long,int)
wait(long)
getclass()
notify()
notifyall()

可以看到所有的方法均是來自collection 和父類object中的方法,符合我們的預(yù)期結(jié)果。接下來我們進(jìn)入第四步和第五步的實現(xiàn):

首先,我們來創(chuàng)建這個動態(tài)代理類的實例。那么直接clazzproxy1.newinstance();可不可以呢?顯然是不可以的嘛.我們剛剛說了,動態(tài)生成的這個代理類只有一個構(gòu)造方法,有沒有無參構(gòu)造方法呢?沒有啊.所以,創(chuàng)建 一個參數(shù)的構(gòu)造方法.參數(shù)類型是java.lang.reflect.invocationhandler。 

JAVA提高第八篇 動態(tài)代理技術(shù)

下面我們來實現(xiàn):

1.定義一個上述接口的實例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package study.javaenhance;
 
import java.lang.reflect.invocationhandler;
import java.lang.reflect.method;
 
public class myinvocationhandler implements invocationhandler {
 
 @override
 public object invoke(object proxy, method method, object[] args)
   throws throwable {
  // todo auto-generated method stub
  return null;
 }
 
}

2.調(diào)用實現(xiàn)創(chuàng)建實例動態(tài)類:

?
1
2
3
4
5
6
7
8
//3.創(chuàng)建實例對象
  system.out.println("----------begin create instance object----------");
  constructor constructor = clazzproxy1.getconstructor(invocationhandler.class);
  myinvocationhandler myinvocationhandler = new myinvocationhandler();
  collection collection = (collection) constructor.newinstance(myinvocationhandler);
  system.out.println(collection);
  collection.clear();
  //collection.size(); //報錯,異常會發(fā)生,產(chǎn)生異常的原因在于其返回值為int類型,但是每一次調(diào)用一個方法都會調(diào)用到invoke方法,我們此時的invoke返回的為null,所以是沒有辦法轉(zhuǎn)換為int類型的。

3.我們采用匿名內(nèi)部類的方式優(yōu)化:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//3.1 采用匿名內(nèi)部類方式進(jìn)行創(chuàng)建
  collection collection2 = (collection) constructor.newinstance(new invocationhandler()
  {
 
   @override
   public object invoke(object proxy, method method, object[] args)
     throws throwable {
    // todo auto-generated method stub
    return null;
   }
   
  });
  system.out.println(collection2);
  collection2.clear();
  //collection2.size();

4.繼續(xù)優(yōu)化:思考如果我們每次都想上面方式去創(chuàng)建動態(tài)的代理類實在有點重復(fù),那么這個是jdk的proxy類中提供了簡單的方法直接去創(chuàng)建動態(tài)代理類,方式如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//3.3 采用proxy 中提供的簡單方法創(chuàng)建
  collection collection3 = (collection)proxy.newproxyinstance(collection.class.getclassloader(),
    new class[]{collection.class},
    new invocationhandler()
  {
   private arraylist target = new arraylist();
   @override
   public object invoke(object proxy, method method, object[] args)
     throws throwable {
    return method.invoke(target, args);
   }
   
  });
  //system.out.println(collection3);
  collection3.add("abc");
  collection3.add("def");
  collection3.add("hij");
  system.out.println(collection3.size());

三、動態(tài)代理的原理簡單分析

上面我們創(chuàng)建了動態(tài)代理類,下面我們分析下代理的原理:

 JAVA提高第八篇 動態(tài)代理技術(shù)

 下面在來看一個問題:

JAVA提高第八篇 動態(tài)代理技術(shù)

動態(tài)代理的工作原理圖:

JAVA提高第八篇 動態(tài)代理技術(shù)

對上面的這個圖,我們簡單來說說:客戶端動態(tài)生成代理類,然后調(diào)用代理類的方法,代理類內(nèi)部調(diào)用handler.invoke()方法,在invoke中呢,我們又指向的目標(biāo)類.這樣就實現(xiàn)了代理了.我客戶端調(diào)用代理的什么方法,invoke就只向目標(biāo)類的同一個方法.而在指定目標(biāo)類方法的前后呢,我們還可以做其他的操作,比如記錄日志.圖中用圈圈出來的部分就是代理類自己實現(xiàn)的功能了.這就是代理類的原理.

JAVA提高第八篇 動態(tài)代理技術(shù)

我們來做最后一步,將上面的動態(tài)生成的代理類,編寫可生成代理和插入通告的通用方法:

 JAVA提高第八篇 動態(tài)代理技術(shù)

test代碼:

?
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
123
124
125
126
127
package study.javaenhance;
 
import java.lang.reflect.constructor;
import java.lang.reflect.invocationhandler;
import java.lang.reflect.method;
import java.lang.reflect.proxy;
import java.util.arraylist;
import java.util.collection;
 
public class proxytest
{
 public static void main(string[] args) throws exception
 {
  class clazzproxy1 = proxy.getproxyclass(collection.class.getclassloader(),collection.class);
  system.out.println(clazzproxy1.getname());
  
  //上面輸出的為一個類,那么一個類肯定有其構(gòu)造方法和方法,下面我們來列出來
  
  system.out.println("----------begin constructors list----------");
  //1.列出構(gòu)造方法
  constructor[] constructors = clazzproxy1.getconstructors();
  for (constructor constructor : constructors)
  {
   string name = constructor.getname();
   stringbuilder sbuilder = new stringbuilder(name);
   sbuilder.append('(');
   class[] clazzparams = constructor.getparametertypes();
   for (class clazzparam : clazzparams) {
    sbuilder.append(clazzparam.getname()).append(',');
   }
   if(clazzparams!=null && clazzparams.length != 0)
    sbuilder.deletecharat(sbuilder.length()-1);
   sbuilder.append(')');
   system.out.println(sbuilder.tostring());
  }
  
  //2.列出這個類字節(jié)碼中的所有方法
  system.out.println("----------begin methods list----------");
  method[] methods = clazzproxy1.getmethods();
  for(method method : methods){
   string name = method.getname();
   stringbuilder sbuilder = new stringbuilder(name);
   sbuilder.append('(');
   class[] clazzparams = method.getparametertypes();
   for(class clazzparam : clazzparams){
    sbuilder.append(clazzparam.getname()).append(',');
   }
   if(clazzparams!=null && clazzparams.length != 0)
    sbuilder.deletecharat(sbuilder.length()-1);
   sbuilder.append(')');
   system.out.println(sbuilder.tostring());  
  }
  
  //3.創(chuàng)建實例對象
  system.out.println("----------begin create instance object----------");
  constructor constructor = clazzproxy1.getconstructor(invocationhandler.class);
  myinvocationhandler myinvocationhandler = new myinvocationhandler();
  collection collection = (collection) constructor.newinstance(myinvocationhandler);
  system.out.println(collection);
  collection.clear();
  //collection.size(); //報錯,異常會發(fā)生,產(chǎn)生異常的原因在于其返回值為int類型,但是每一次調(diào)用一個方法都會調(diào)用到invoke方法,我們此時的invoke返回的為null,所以是沒有辦法轉(zhuǎn)換為int類型的。
  
  //3.1 采用匿名內(nèi)部類方式進(jìn)行創(chuàng)建
  collection collection2 = (collection) constructor.newinstance(new invocationhandler()
  {
 
   @override
   public object invoke(object proxy, method method, object[] args)
     throws throwable {
    // todo auto-generated method stub
    return null;
   }
   
  });
  system.out.println(collection2);
  collection2.clear();
  //collection2.size();
  
  //3.3 采用proxy 中提供的簡單方法創(chuàng)建
  collection collection3 = (collection)proxy.newproxyinstance(collection.class.getclassloader(),
    new class[]{collection.class},
    new invocationhandler()
  {
   private arraylist target = new arraylist();
   @override
   public object invoke(object proxy, method method, object[] args)
     throws throwable {
    return method.invoke(target, args);
   }
   
  });
  //system.out.println(collection3);
  collection3.add("abc");
  collection3.add("def");
  collection3.add("hij");
  system.out.println(collection3.size());
  system.out.println(collection3.getclass().getname());//這個返回的是
  
  system.out.println("----------begin create instance object 抽化----------");
  //3.4抽出動態(tài)代理讓目標(biāo)對象和切面對象都是傳入進(jìn)去的
  
  final arraylist target = new arraylist();
  collection collection4 = (collection)getproxy(target,new myadvice());
  collection4.add("test1");
  collection4.add("test2");
  system.out.println(collection4.size());
 }
 
 private static object getproxy(final object target,final advice advice) {
  object object = proxy.newproxyinstance(target.getclass().getclassloader(),
    target.getclass().getinterfaces(),
    new invocationhandler()
  {
   @override
   public object invoke(object proxy, method method, object[] args)
     throws throwable {
    advice.beforemethod(method);
    object retvalue = method.invoke(target, args);
    advice.aftermethod(method);
    return retvalue;
   }
   
  });
  return object;
 }
 
}

四、實現(xiàn)類似spring的可配置的aop框架

首先,我們要完成的要求如下:

JAVA提高第八篇 動態(tài)代理技術(shù)

我們來模擬spring的工廠模式讀取從配置文件傳遞過來的類。如果這個類是一個普通類則直接返回。如果是一個代理類,則創(chuàng)建代理對象,返回代理類。

具體的理論知識可以看上面的圖片

首先創(chuàng)建一個beanfactory.java類。這是一個bean工廠,用于讀取配置文件中的類

?
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
package study.javaenhance.aopframework;
 
import java.io.ioexception;
import java.io.inputstream;
import java.util.properties;
 
import study.javaenhance.advice;
 
public class beanfactory
{
 private properties properties = new properties();
 
 
 public beanfactory(inputstream instream)
 {
  try
  {
   properties.load(instream);
  }
  catch (ioexception e)
  {
   e.printstacktrace();
  }
  finally
  {
   if(instream != null)
   {
    try
    {
     instream.close();
    }
    catch (ioexception e)
    {
     e.printstacktrace();
    }
   }
  }
 }
 
 
 public object getbean(string name)
 {
  string classname = properties.getproperty(name);
  object bean = null;
  try
  {
   class clazz = class.forname(classname);
   bean = clazz.newinstance();
   if(bean instanceof proxyfactorybean)
   {
    proxyfactorybean proxybean = (proxyfactorybean) bean;
    advice advice = (advice)class.forname(properties.getproperty(name + ".advice")).newinstance();
    object target = class.forname(properties.getproperty(name + ".target")).newinstance();
    proxybean.setadvice(advice);
    proxybean.settarget(target);
    object proxy = proxybean.getproxy();
    return proxy;
   }
  }
  catch (exception e)
  {
   // todo auto-generated catch block
   e.printstacktrace();
  }
  return bean;
 }
}

如果這個類中包含proxyfactorybean,則調(diào)用proxyfactorybean中的getproxy方法。動態(tài)生成代理類。
proxyfactorybean.java

?
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
package study.javaenhance.aopframework;
 
import java.lang.reflect.invocationhandler;
import java.lang.reflect.method;
import java.lang.reflect.proxy;
 
import study.javaenhance.advice;
 
public class proxyfactorybean
{
 
 private object target;
 
 private advice advice;
 
 
 public object gettarget() {
  return target;
 }
 
 
 public void settarget(object target) {
  this.target = target;
 }
 
 
 public advice getadvice() {
  return advice;
 }
 
 
 public void setadvice(advice advice) {
  this.advice = advice;
 }
 
 
 public object getproxy()
 {
  object object = proxy.newproxyinstance(target.getclass().getclassloader(),target.getclass().getinterfaces(),
    new invocationhandler()
  {
 
   @override
   public object invoke(object proxy, method method, object[] args)
     throws throwable {
    advice.beforemethod(method);
    object retvalue = method.invoke(target, args);
    advice.aftermethod(method);
    return retvalue;
   }
   
  });
  return object;
 }
 
}

接下來創(chuàng)建一個config.properties文件.config.properties

xxx=java.util.arraylist
#xxx=study.javaenhance.aopframework.proxyfactorybean
xxx.advice=study.javaenhance.myadvice
xxx.target=java.util.arraylist

最后建立測試類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package study.javaenhance.aopframework;
 
import java.io.inputstream;
import java.util.collection;
 
public class aopframeworktest
{
 public static void main(string[] args)
 {
  inputstream ips = aopframeworktest.class.getresourceasstream("config.properties");
  object bean = new beanfactory(ips).getbean("xxx");
  system.out.println(bean.getclass().getname());
  ((collection)bean).clear();
 }
 
}

測試ok

總結(jié):整個java增強(qiáng)的視頻學(xué)習(xí)完成了,一共記住了多少我也不知道.但知道了很多內(nèi)在的知識,如果有時間的話,或者說過一段時間可以拿出來問下,提供自己的技能。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

原文鏈接:http://www.cnblogs.com/pony1223/p/7719766.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: av中文字幕网免费观看 | 精新精新国产自在现 | 精品丰满人妻无套内射 | 国产成人精品高清不卡在线 | 貂蝉沦为姓奴小说 | 亚洲国产一区二区三区a毛片 | 高清在线一区二区 | 精品一区二区三区免费视频 | 国产午夜精品一区二区三区不卡 | 91日本在线 | 99ri在线精品视频 | 日本成年片高清在线观看 | 欧美一区二区三区综合色视频 | www.精品视频 | blacked黑人hd2021| 青青草原国产视频 | 欧美日韩精品一区二区三区高清视频 | 欧美色综合高清免费 | 国产精品亚洲片在线观看麻豆 | 2019年国产不卡在线刷新 | 91在线精品视频 | chinaese中国女人厕所小便 | 午夜免费无码福利视频麻豆 | 日本免费三片在线观看 | 果冻传媒在线播放观看w | 猫咪免费人成网站在线观看入口 | 日本人成在线视频免费播放 | beeg xxxx日本 | 色中色软件 | 91赵邦贺| 高中生放荡日记高h娜娜 | 天若有情1992国语版完整版 | 免费在线看 | 亚飞与亚基国语1080p在线观看 | 亚洲国产天堂在线观看 | 娇妻终于接受了3p的调教 | naruto堂同人本子汉化gg | 四虎成人网 | 四虎院影永久在线观看 | 亚洲男人天堂久久 | 国产精品第2页 |