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

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

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語言 - JAVA教程 - 詳解設(shè)計(jì)模式中的proxy代理模式及在Java程序中的實(shí)現(xiàn)

詳解設(shè)計(jì)模式中的proxy代理模式及在Java程序中的實(shí)現(xiàn)

2020-05-01 13:40pastqing JAVA教程

代理模式主要分為靜態(tài)代理和動(dòng)態(tài)代理,使客戶端方面的使用者通過設(shè)置的代理來操作對(duì)象,下面來詳解設(shè)計(jì)模式中的proxy代理模式及在Java程序中的實(shí)現(xiàn)

一、代理模式定義

給某個(gè)對(duì)象提供一個(gè)代理對(duì)象,并由代理對(duì)象控制對(duì)于原對(duì)象的訪問,即客戶不直接操控原對(duì)象,而是通過代理對(duì)象間接地操控原對(duì)象。
著名的代理模式的例子就是引用計(jì)數(shù)(reference counting): 當(dāng)需要一個(gè)復(fù)雜對(duì)象的多份副本時(shí), 代理模式可以結(jié)合享元模式以減少存儲(chǔ)器的用量。典型做法是創(chuàng)建一個(gè)復(fù)雜對(duì)象以及多個(gè)代理者, 每個(gè)代理者會(huì)引用到原本的對(duì)象。而作用在代理者的運(yùn)算會(huì)轉(zhuǎn)送到原本對(duì)象。一旦所有的代理者都不存在時(shí), 復(fù)雜對(duì)象會(huì)被移除。

要理解代理模式很簡單,其實(shí)生活當(dāng)中就存在代理模式:
我們購買火車票可以去火車站買,但是也可以去火車票代售處買,此處的火車票代售處就是火車站購票的代理,即我們?cè)诖埸c(diǎn)發(fā)出買票請(qǐng)求,代售點(diǎn)會(huì)把請(qǐng)求發(fā)給火車站,火車站把購買成功響應(yīng)發(fā)給代售點(diǎn),代售點(diǎn)再告訴你。
但是代售點(diǎn)只能買票,不能退票,而火車站能買票也能退票,因此代理對(duì)象支持的操作可能和委托對(duì)象的操作有所不同。

再舉一個(gè)寫程序會(huì)碰到的一個(gè)例子:
如果現(xiàn)在有一個(gè)已有項(xiàng)目(你沒有源代碼,只能調(diào)用它)能夠調(diào)用 int compute(String exp1) 實(shí)現(xiàn)對(duì)于后綴表達(dá)式的計(jì)算,你想使用這個(gè)項(xiàng)目實(shí)現(xiàn)對(duì)于中綴表達(dá)式的計(jì)算,那么你可以寫一個(gè)代理類,并且其中也定義一個(gè)compute(String exp2),這個(gè)exp2參數(shù)是中綴表達(dá)式,因此你需要在調(diào)用已有項(xiàng)目的 compute() 之前將中綴表達(dá)式轉(zhuǎn)換成后綴表達(dá)式(Preprocess),再調(diào)用已有項(xiàng)目的compute(),當(dāng)然你還可以接收到返回值之后再做些其他操作比如存入文件(Postprocess),這個(gè)過程就是使用了代理模式。

在平時(shí)用電腦也會(huì)碰到代理模式的應(yīng)用:
遠(yuǎn)程代理:我們?cè)趪鴥?nèi)因?yàn)镚FW,所以不能訪問 facebook,我們可以用翻墻(設(shè)置代理)的方法訪問。訪問過程是:
(1)用戶把HTTP請(qǐng)求發(fā)給代理
(2)代理把HTTP請(qǐng)求發(fā)給web服務(wù)器
(3)web服務(wù)器把HTTP響應(yīng)發(fā)給代理
(4)代理把HTTP響應(yīng)發(fā)回給用戶


二、靜態(tài)代理

所謂靜態(tài)代理, 就是在編譯階段就生成代理類來完成對(duì)代理對(duì)象的一系列操作。下面是代理模式的結(jié)構(gòu)類圖:

1、代理模式的參與者

代理模式的角色分四種:

主題接口: 即代理類的所實(shí)現(xiàn)的行為接口。
目標(biāo)對(duì)象: 也就是被代理的對(duì)象。
代理對(duì)象: 用來封裝真是主題類的代理類
客戶端
下面是代理模式的類圖結(jié)構(gòu):

詳解設(shè)計(jì)模式中的proxy代理模式及在Java程序中的實(shí)現(xiàn)

2、代理模式的實(shí)現(xiàn)思路

代理對(duì)象和目標(biāo)對(duì)象均實(shí)現(xiàn)同一個(gè)行為接口。
代理類和目標(biāo)類分別具體實(shí)現(xiàn)接口邏輯。
在代理類的構(gòu)造函數(shù)中實(shí)例化一個(gè)目標(biāo)對(duì)象。
在代理類中調(diào)用目標(biāo)對(duì)象的行為接口。
客戶端想要調(diào)用目標(biāo)對(duì)象的行為接口,只能通過代理類來操作。
3、靜態(tài)代理的實(shí)例

下面以一個(gè)延遲加載的例子來說明一下靜態(tài)代理。我們?cè)趩?dòng)某個(gè)服務(wù)系統(tǒng)時(shí), 加載某一個(gè)類時(shí)可能會(huì)耗費(fèi)很長時(shí)間。為了獲取更好的性能, 在啟動(dòng)系統(tǒng)的時(shí)候, 我們往往不去初始化這個(gè)復(fù)雜的類, 取而代之的是去初始化其代理類。這樣將耗費(fèi)資源多的方法使用代理進(jìn)行分離, 可以加快系統(tǒng)的啟動(dòng)速度, 減少用戶等待的時(shí)間。

定義一個(gè)主題接口

?
1
2
3
4
public interface Subject {
  public void sayHello();
  public void sayGoodBye();
}

定義一個(gè)目標(biāo)類, 并實(shí)現(xiàn)主題接口

?
1
2
3
4
5
6
7
8
public class RealSubject implements Subject {
  public void sayHello() {
    System.out.println("Hello World");
  }
  public void sayGoodBye() {
    System.out.println("GoodBye World");
  }
}

定義一個(gè)代理類, 來代理目標(biāo)對(duì)象。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class StaticProxy implements Subject {
  Private RealSubject realSubject = null;
  public StaticProxy() {}
  public void sayHello() {
    //用到時(shí)候才加載, 懶加載
    if(realSubject == null) {
      realSubject = new RealSubject();
    }
    realSubject.sayHello();
  }
  //sayGoodbye方法同理
  ...
}

定義一個(gè)客戶端

?
1
2
3
4
5
6
7
public class Client {
  public static void main(String [] args) {
    StaticProxy sp = new StaticProxy();
    sp.sayHello();
    sp.sayGoodBye();
  }
}

以上就是靜態(tài)代理的一個(gè)簡單測試?yán)印8杏X可能沒有實(shí)際用途。然而并非如此。使用代理我們還可以將目標(biāo)對(duì)象的方法進(jìn)行改造, 比如數(shù)據(jù)庫連接池中創(chuàng)建了一系列連接, 為了保證不頻繁的打開連接,這些連接是幾乎不會(huì)關(guān)閉的。然而我們編程總有習(xí)慣去將打開的Connection去close。 這樣我們就可以利用代理模式來重新代理Connection接口中的close方法, 改變?yōu)榛厥盏綌?shù)據(jù)庫連接池中而不是真正的執(zhí)行Connection#close方法。其他的例子還有很多, 具體需要自己體會(huì)。

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

動(dòng)態(tài)代理是指在運(yùn)行時(shí)動(dòng)態(tài)生成代理類。即,代理類的字節(jié)碼將在運(yùn)行時(shí)生成并載入當(dāng)前代理的 ClassLoader。與靜態(tài)處理類相比,動(dòng)態(tài)類有諸多好處。

不需要為真實(shí)主題寫一個(gè)形式上完全一樣的封裝類,假如主題接口中的方法很多,為每一個(gè)接口寫一個(gè)代理方法也很麻煩。如果接口有變動(dòng),則真實(shí)主題和代理類都要修改,不利于系統(tǒng)維護(hù);
使用一些動(dòng)態(tài)代理的生成方法甚至可以在運(yùn)行時(shí)制定代理類的執(zhí)行邏輯,從而大大提升系統(tǒng)的靈活性。
生成動(dòng)態(tài)代理的方法有很多: JDK中自帶動(dòng)態(tài)代理, CGlib, javassist等。這些方法各有優(yōu)缺點(diǎn)。本文主要探究JDK中的動(dòng)態(tài)代理的使用和源碼分析。

下面用一個(gè)實(shí)例講解一下JDK中動(dòng)態(tài)代理的用法:

?
1
2
3
4
5
6
7
8
9
10
public class dynamicProxy implements InvocationHandler {
  private RealSubject = null;
  public Object invoke(Object proxy, Method method, Object[] args){
    if(RealSubject == null) {
      RealSubject = new RealSubject();
    }
    method.invoke(RealSubject, args);
    return RealSubject;
  }
}

客戶端代碼實(shí)例

?
1
2
3
4
5
6
7
public class Client {
  public static void main(Strings[] args) {
    Subject subject = (Subject)Proxy.newInstance(ClassLoader.getSystemLoader(), RealSubject.class.getInterfaces(), new DynamicProxy());
    Subject.sayHello();
    Subject.sayGoodBye();
  }
}

從上面的代碼可以看出, 要利用JDK中的動(dòng)態(tài)代理。利用靜態(tài)方法Proxy.newInstance(ClassLoader, Interfaces[], InvokeHandler)可以創(chuàng)建一個(gè)動(dòng)態(tài)代理類。 newInstance方法有三個(gè)參數(shù), 分別表示類加載器, 一個(gè)希望該代理類實(shí)現(xiàn)的接口列表, 以及實(shí)現(xiàn)InvokeHandler接口的實(shí)例。 動(dòng)態(tài)代理將每個(gè)方法的執(zhí)行過程則交給了Invoke方法處理。

JDK動(dòng)態(tài)代理要求, 被代理的必須是個(gè)接口, 單純的類則不行。JDK動(dòng)態(tài)代理所生成的代理類都會(huì)繼承Proxy類,同時(shí)代理類會(huì)實(shí)現(xiàn)所有你傳入的接口列表。因此可以強(qiáng)制類型轉(zhuǎn)換成接口類型。 下面是Proxy的結(jié)構(gòu)圖。

詳解設(shè)計(jì)模式中的proxy代理模式及在Java程序中的實(shí)現(xiàn)

可以看出Proxy全是靜態(tài)方法, 因此如果代理類沒有實(shí)現(xiàn)任何接口, 那么他就是Proxy類型, 沒有實(shí)例方法。

當(dāng)然加入你要是非要代理一個(gè)沒有實(shí)現(xiàn)某個(gè)接口的類, 同時(shí)該類的方法與其他接口定義的方法相同, 利用反射也是可以輕松實(shí)現(xiàn)的。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class DynamicProxy implements InvokeHandler {
  //你想代理的類
  private TargetClass targetClass = null;
  //初始化該類
  public DynamicProxy(TargetClass targetClass) {
    this.targetClass = targetClass;
  }
  public Object invoke(Object proxy, Method method, Object[] args) {
    //利用反射獲取你想代理的類的方法
    Method myMethod = targetClass.getClass().getDeclaredMethod(method.getName(), method.getParameterTypes());
    myMethod.setAccessible(true);
    return myMethod.invoke(targetClass, args);
  }
}

四、JDK動(dòng)態(tài)代理源碼分析(JDK7)

看了上面的例子, 我們只是簡單會(huì)用動(dòng)態(tài)代理。但是對(duì)于代理類是如何創(chuàng)建出來的, 是誰調(diào)用Invoke方法等還云里霧里。下面通過分析

1、代理對(duì)象是如何創(chuàng)建出來的?

首先看Proxy.newInstance方法的源碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
  }
  //獲取接口信息
  final Class<?>[] intfs = interfaces.clone();
  final SecurityManager sm = System.getSecurityManager();
  if (sm != null) {
    checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
  }
  //生成代理類
  Class<?> cl = getProxyClass0(loader, intfs);
  // ...OK我們先看前半截
  }

從源碼看出代理類的生成是依靠getProxyClass0這個(gè)方法, 接下來看getProxyClass0源碼:

?
1
2
3
4
5
6
7
8
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
  //接口列表數(shù)目不能超過0xFFFF
  if (interfaces.length > 65535) {
    throw new IllegalArgumentException("interface limit exceeded");
  }
  //注意這里, 下面詳細(xì)解釋
    return proxyClassCache.get(loader, interfaces);
  }

對(duì)proxyClassCache.get的解釋是: 如果實(shí)現(xiàn)接口列表的代理類已經(jīng)存在,那么直接從cache中拿。如果不存在, 則通過ProxyClassFactory生成一個(gè)。
在看proxyClassCache.get源碼之前,先簡單了解一下proxyClassCache:

?
1
2
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
   proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

proxyClassCache是一個(gè)WeakCache類型的緩存, 它的構(gòu)造函數(shù)有兩個(gè)參數(shù), 其中一個(gè)就是用于生成代理類的ProxyClassFactory, 下面是proxyClassCache.get的源碼:

?
1
2
3
4
final class WeakCache<K, P, V> {
  ...
  public V get(K key, P parameter) {}
}

這里K表示key, P表示parameters, V表示value

?
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
public V get(K key, P parameter) {
  //java7 NullObject判斷方法, 如果parameter為空則拋出帶有指定消息的異常。 如果不為空則返回。
  Objects.requireNonNull(parameter);
  //清理持有弱引用的WeakHashMap這種數(shù)據(jù)結(jié)構(gòu),一般用于緩存
  expungeStaleEntries();
  //從隊(duì)列中獲取cacheKey
  Object cacheKey = CacheKey.valueOf(key, refQueue);
  //利用懶加載的方式填充Supplier, Concurrent是一種線程安全的map
  ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
  if (valuesMap == null) {
    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中獲取Value,這個(gè)Value可能是一個(gè)工廠或者Cache的實(shí)
    //下面這三句代碼是核心代碼, 返回實(shí)現(xiàn)InvokeHandler的類并包含了所需要的信息。
    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)
    //下面這個(gè)過程就是填充supplier的過程
    if(factory == null) {
      //創(chuàng)建一個(gè)factory
    }
    if(supplier == null) {
      //填充supplier
    }else {
      //填充supplier
    }
  }

while循環(huán)的作用就是不停的獲取實(shí)現(xiàn)InvokeHandler的類, 這個(gè)類可以是從緩存中拿到,也可是是從proxyFactoryClass生成的。
Factory是一個(gè)實(shí)現(xiàn)了Supplier<V>接口的內(nèi)部類。這個(gè)類覆蓋了get方法, 在get方法中調(diào)用了類型為proxyFactoryClass的實(shí)例方法apply。這個(gè)方法才是真正創(chuàng)建代理類的方法。下面看ProxyFactoryClass#apply方法的源碼:

?
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
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 {
      //加載每一個(gè)接口運(yùn)行時(shí)的信息
      interfaceClass = Class.forName(intf.getName(), false, loader);
    } catch (ClassNotFoundException e) {
    }
  //如果使用你自己的classload加載的class與你傳入的class不相等,拋出異常
  if (interfaceClass != intf) {
    throw new IllegalArgumentException(
    intf + " is not visible from class loader");
  }
  //如果傳入不是一個(gè)接口類型
    if (!interfaceClass.isInterface()) {
      throw new IllegalArgumentException(
        interfaceClass.getName() + " is not an interface");
    }
   //驗(yàn)證接口是否重復(fù)
    if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
      throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());
    }
  }
  String proxyPkg = null;   // package to define proxy class in
  /* 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.
  */
  //這一段是看你傳入的接口中有沒有不是public的接口,如果有,這些接口必須全部在一個(gè)包里定義的,否則拋異常
  for (Class<?> intf : interfaces) {
    int flags = intf.getModifiers();
    if (!Modifier.isPublic(flags)) {
      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();
  //生成隨機(jī)代理類的類名, $Proxy + num
  String proxyName = proxyPkg + proxyClassNamePrefix + num;
  /*
  * 生成代理類的class文件, 返回字節(jié)流
  */
  byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);
  try {
    return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
  } catch (ClassFormatError e) {
        //結(jié)束
        throw new IllegalArgumentException(e.toString());
      }
    }
  }

前文提到ProxyFactoryClass#apply是真正生成代理類的方法, 這其實(shí)是不準(zhǔn)確的。源代碼讀到這里,我們會(huì)發(fā)現(xiàn)ProxyGenerator#generateProxyClass才是真正生成代理類的方法。根據(jù)Java class字節(jié)碼組成(可以參見我的另一篇文章Java字節(jié)碼學(xué)習(xí)筆記)來生成相應(yīng)的Clss文件。具體ProxyGenerator#generateProxyClass源碼如下:

?
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
private byte[] generateClassFile() {
   /*
    * Step 1: Assemble ProxyMethod objects for all methods to
    * generate proxy dispatching code for.
    */
    //addProxyMethod方法,就是將方法都加入到一個(gè)列表中,并與對(duì)應(yīng)的class對(duì)應(yīng)起來
   //這里給Object對(duì)應(yīng)了三個(gè)方法hashCode,toString和equals
   addProxyMethod(hashCodeMethod, Object.class);
   addProxyMethod(equalsMethod, Object.class);
   addProxyMethod(toStringMethod, Object.class);
   //將接口列表中的接口與接口下的方法對(duì)應(yīng)起來
   for (int i = 0; i < interfaces.length; i++) {
     Method[] methods = interfaces[i].getMethods();
     for (int j = 0; j < methods.length; j++) {
       addProxyMethod(methods[j], interfaces[i]);
     }
   }
   /*
    * For each set of proxy methods with the same signature,
    * verify that the methods' return types are compatible.
    */
   for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
     checkReturnTypes(sigmethods);
   }
   /*
    * Step 2: Assemble FieldInfo and MethodInfo structs for all of
    * fields and methods in the class we are generating.
    */
    //方法中加入構(gòu)造方法,這個(gè)構(gòu)造方法只有一個(gè),就是一個(gè)帶有InvocationHandler接口的構(gòu)造方法
    //這個(gè)才是真正給class文件,也就是代理類加入方法了,不過還沒真正處理,只是先加進(jìn)來等待循環(huán),構(gòu)造方法在class文件中的名稱描述是<init>
 try {
   methods.add(generateConstructor());
   for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
     for (ProxyMethod pm : sigmethods) {
//給每一個(gè)代理方法加一個(gè)Method類型的屬性,數(shù)字10是class文件的標(biāo)識(shí)符,代表這些屬性都是private static的
       fields.add(new FieldInfo(pm.methodFieldName,
         "Ljava/lang/reflect/Method;",
          ACC_PRIVATE | ACC_STATIC));
       //將每一個(gè)代理方法都加到代理類的方法中
       methods.add(pm.generateMethod());
     }
   }
 //加入一個(gè)靜態(tài)初始化塊,將每一個(gè)屬性都初始化,這里靜態(tài)代碼塊也叫類構(gòu)造方法,其實(shí)就是名稱為<clinit>的方法,所以加到方法列表
     methods.add(generateStaticInitializer());
   } catch (IOException e) {
     throw new InternalError("unexpected I/O Exception");
   }
 //方法和屬性個(gè)數(shù)都不能超過65535,包括之前的接口個(gè)數(shù)也是這樣,
 //這是因?yàn)樵赾lass文件中,這些個(gè)數(shù)都是用4位16進(jìn)制表示的,所以最大值是2的16次方-1
   if (methods.size() > 65535) {
     throw new IllegalArgumentException("method limit exceeded");
   }
   if (fields.size() > 65535) {
     throw new IllegalArgumentException("field limit exceeded");
   }
 //接下來就是寫class文件的過程, 包括魔數(shù), 類名,常量池等一系列字節(jié)碼的組成,就不一一細(xì)說了。需要的可以參考JVM虛擬機(jī)字節(jié)碼的相關(guān)知識(shí)。
   cp.getClass(dotToSlash(className));
   cp.getClass(superclassName);
   for (int i = 0; i < interfaces.length; i++) {
     cp.getClass(dotToSlash(interfaces[i].getName()));
   }
   cp.setReadOnly();
   ByteArrayOutputStream bout = new ByteArrayOutputStream();
   DataOutputStream dout = new DataOutputStream(bout);
   try {
                   // u4 magic;
     dout.writeInt(0xCAFEBABE);
                   // u2 minor_version;
     dout.writeShort(CLASSFILE_MINOR_VERSION);
                   // u2 major_version;
     dout.writeShort(CLASSFILE_MAJOR_VERSION);
     cp.write(dout);       // (write constant pool)
                   // u2 access_flags;
     dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER);
                   // u2 this_class;
     dout.writeShort(cp.getClass(dotToSlash(className)));
                   // u2 super_class;
     dout.writeShort(cp.getClass(superclassName));
                   // u2 interfaces_count;
     dout.writeShort(interfaces.length);
                   // u2 interfaces[interfaces_count];
     for (int i = 0; i < interfaces.length; i++) {
       dout.writeShort(cp.getClass(
         dotToSlash(interfaces[i].getName())));
     }
                   // u2 fields_count;
     dout.writeShort(fields.size());
                   // field_info fields[fields_count];
     for (FieldInfo f : fields) {
       f.write(dout);
     }
                   // u2 methods_count;
     dout.writeShort(methods.size());
                   // method_info methods[methods_count];
     for (MethodInfo m : methods) {
       m.write(dout);
     }
                    // u2 attributes_count;
     dout.writeShort(0); // (no ClassFile attributes for proxy classes)
   } catch (IOException e) {
     throw new InternalError("unexpected I/O Exception");
   }
   return bout.toByteArray();
 }

經(jīng)過層層調(diào)用, 一個(gè)代理類終于生成了。

2、是誰調(diào)用了Invoke?

我們模擬JDK自己生成一個(gè)代理類, 類名為TestProxyGen:

?
1
2
3
4
5
6
7
8
9
10
public class TestGeneratorProxy {
  public static void main(String[] args) throws IOException {
    byte[] classFile = ProxyGenerator.generateProxyClass("TestProxyGen", Subject.class.getInterfaces());
    File file = new File("/Users/yadoao/Desktop/TestProxyGen.class");
    FileOutputStream fos = new FileOutputStream(file);
    fos.write(classFile);
    fos.flush();
    fos.close();
  }
}

用JD-GUI反編譯該class文件, 結(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
import com.su.dynamicProxy.ISubject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class TestProxyGen extends Proxy
 implements ISubject
{
 private static Method m3;
 private static Method m1;
 private static Method m0;
 private static Method m4;
 private static Method m2;
 public TestProxyGen(InvocationHandler paramInvocationHandler)
  throws
 {
  super(paramInvocationHandler);
 }
 public final void sayHello()
  throws
 {
  try
  {
   this.h.invoke(this, m3, null);
   return;
  }
  catch (Error|RuntimeException localError)
  {
   throw localError;
  }
  catch (Throwable localThrowable)
  {
   throw new UndeclaredThrowableException(localThrowable);
  }
 }
 public final boolean equals(Object paramObject)
  throws
 {
  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 int hashCode()
  throws
 {
  try
  {
   return ((Integer)this.h.invoke(this, m0, null)).intValue();
  }
  catch (Error|RuntimeException localError)
  {
   throw localError;
  }
  catch (Throwable localThrowable)
  {
   throw new UndeclaredThrowableException(localThrowable);
  }
 }
 public final void sayGoodBye()
  throws
 {
  try
  {
   this.h.invoke(this, m4, null);
   return;
  }
  catch (Error|RuntimeException localError)
  {
   throw localError;
  }
  catch (Throwable localThrowable)
  {
   throw new UndeclaredThrowableException(localThrowable);
  }
 }
 public final String toString()
  throws
 {
  try
  {
   return (String)this.h.invoke(this, m2, null);
  }
  catch (Error|RuntimeException localError)
  {
   throw localError;
  }
  catch (Throwable localThrowable)
  {
   throw new UndeclaredThrowableException(localThrowable);
  }
 }
 static
 {
  try
  {
   m3 = Class.forName("com.su.dynamicProxy.ISubject").getMethod("sayHello", new Class[0]);
   m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
   m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
   m4 = Class.forName("com.su.dynamicProxy.ISubject").getMethod("sayGoodBye", new Class[0]);
   m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
   return;
  }
  catch (NoSuchMethodException localNoSuchMethodException)
  {
   throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
  }
  catch (ClassNotFoundException localClassNotFoundException)
  {
   throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
  }
 }
}

首先注意到生成代理類的構(gòu)造函數(shù), 它傳入一個(gè)實(shí)現(xiàn)InvokeHandler接口的類作為參數(shù), 并調(diào)用父類Proxy的構(gòu)造器, 即將Proxy中的成員變量protected InvokeHander h進(jìn)行了初始化。
再次注意到幾個(gè)靜態(tài)的初始化塊, 這里的靜態(tài)初始化塊就是對(duì)代理的接口列表以及hashcode,toString, equals方法進(jìn)行初始化。
最后就是這幾個(gè)方法的調(diào)用過程, 全都是回調(diào)Invoke方法。
就此代理模式分析到此結(jié)束。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 男人的天堂欧美 | 欧美美女一级片 | 亚洲区精品 | www亚洲色图 | 日韩大片免费看 | 毛片手机在线视频免费观看 | 日本高清中文字幕 | 国产精品天天看特色大片不卡 | 26uuu成人人网图片 | 午夜宅男在线观看 | ai换脸杨颖被啪在线观看 | 97porm自拍视频区原创 | 亚洲精品丝袜在线一区波多野结衣 | 四虎影视在线观看2413 | 午夜精品久久久久久久99蜜桃i | 九九99亚洲精品久久久久 | dasd-698黑人在线播放 | 1024免费永久福利视频 | 5g996未满十八 | 国产精品精品 | 精品手机在线视频 | 惩罚美女妲己的尤老师 | 久久国产乱子伦精品免费不卡 | 国产精品毛片久久久久久久 | 5g影院成人 | 双性鞭蒂软汁淋漓 | 国产精品3p视频 | 思敏1一5集国语版免费观看 | 日本老妇人乱视频 | 铁牛tv 在线观看 | 国产一区二区三区久久精品 | 国产成人亚洲精品乱码在线观看 | 91庥豆果冻天美精东蜜桃传媒 | 朝鲜女人性猛交 | 91桃色污 | 亚飞与亚基国语1080p在线观看 | 国产极品精频在线观看 | 视频在线观看入口一二三2021 | 日本国产一区二区三区 | 亚洲人成激情在线播放 | 幻女free性zozo交体内谢 |