1. 程式人生 > >spring設計模式_代理模式

spring設計模式_代理模式

output boolean ins oca 對象的引用 lec leo interface todo

代理模式應該是Spring核心設計模式之一了

先說下代理模式特性:

  1.有代理人和被代理人

  2.對於被代理的人來說,這件事情是一定要做的,但是我又不想做,所有就找代理人來做。

  3.需要獲取到被代理人的個人資料。

現實中的例子:

  黃牛:我需要買票又不想排隊,黃牛拿著我的個人信息代替我買票。。emmmmm不合法,但確實是代理模式

  相親: 我需要女朋友又不主動找女朋友,所以媒婆拿著我的個人條件,代替我去找女朋友??????總感覺哪裏怪怪的

GitHub源碼地址:https://github.com/wujiachengSH/WjcProxyDemo

下面我們來舉個栗子看下代碼中的代理是什麽樣子的

咳咳,來個找對象吧

先定義個接口

package com.wjc.proxy;

public interface People {

	String getHeight();
	
	String getSex();
	
	//擇偶標準
	void getStandardsOfChoosingSpouse();
	
}

來個實現類

 1 package com.wjc.proxy;
 2 
 3 public class Wjc implements People {
 4 
 5     private String height = "170";
6 private String Sex = "男"; 7 8 @Override 9 public String getHeight() { 10 // TODO Auto-generated method stub 11 return height; 12 } 13 14 @Override 15 public String getSex() { 16 // TODO Auto-generated method stub 17 return Sex;
18 } 19 20 @Override 21 public void getStandardsOfChoosingSpouse() { 22 // TODO Auto-generated method stub 23 System.out.println("性別男,愛好女"); 24 System.out.println("不想努力了,求富婆包養"); 25 26 } 27 28 29 30 }

來個代理類,代替我調用我自己,傳說中的害羞。。噗

 1 package com.wjc.proxy;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 import java.lang.reflect.Proxy;
 6 
 7 public class MatchMaker implements InvocationHandler {
 8     // 拿到被代理的對象
 9     private People target;
10 
11     // 獲取被代理對象
12     public Object getInstance(People target) throws Exception {
13         this.target = target;
14         Class clazz = target.getClass();
15         return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
16     }
17 
18     @Override
19     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
20         System.out.println("-------這是一位"+this.target.getSex()+"性-------");
21         
22         method.invoke(this.target, args);
23         System.out.println("找富婆是要付出代價的");
24 
25         return null;
26     }
27 
28 }

測試一下

 1 package com.wjc.proxy;
 2 
 3 public class Test {
 4     public static void main(String[] args) {
 5 
 6         try {
 7             People instance = (People) new MatchMaker().getInstance(new Wjc());
 8             instance.getStandardsOfChoosingSpouse();
 9             
10             instance.getHeight();
11         } catch (Exception e) {
12             // TODO Auto-generated catch block
13             e.printStackTrace();
14         }
15 
16     }
17 }

測試結果

技術分享圖片

通過這個簡單的栗子,看到所謂的代理,其實就是方法增強,嗯,可以拿到對象的所有方法,並且以一定順序來執行。

那麽問題就來了,到底是怎麽實現的呢?

 1 package com.wjc.proxy;
 2 
 3 public class Test2 {
 4     public static void main(String[] args) {
 5 
 6         try {
 7             Wjc wjc = new Wjc();
 8             People instance = (People) new MatchMaker().getInstance(wjc);
 9             System.out.println(wjc.getClass());
10             System.out.println(instance.getClass());
11             
12         } catch (Exception e) {
13             // TODO Auto-generated catch block
14             e.printStackTrace();
15         }
16 
17     }
18 }

執行結果

技術分享圖片

可以看到已經不是原來的類了

在代理的過程中,會使用反射的技巧,重新生成一個類!

大致代理流程如下所示

//1.拿到被代理對象的引用,然後獲取它的接口
//2.JDK代理重新生成一個類,同時實現我們給的代理對象所實現的接口
//3.把被代理對象的引用也拿到了
//4.重新動態生成一個class字節碼
//5.然後編譯

  

我們將技術分享圖片打印並反編譯出來,看看到底都幹啥了

打印類方法

1         byte[] data = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{People.class});
2             FileOutputStream os = new FileOutputStream("E:/$Proxy0.class");
3             os.write(data);
4             os.close();

通過小工具(luyten) 下載地址:https://github.com/deathmarine/Luyten/releases/tag/v0.5.4

可以看到,創建的類獲取了對象的hashcode,equals,toString和其自有方法來創建了一個新類

所有在使用代理時,此類就是代理人,被他反射的方法的對象就是被代理人

  1 import com.wjc.proxy.*;
  2 import java.lang.reflect.*;
  3 
  4 public final class $Proxy0 extends Proxy implements People
  5 {
  6     private static Method m1;
  7     private static Method m4;
  8     private static Method m2;
  9     private static Method m3;
 10     private static Method m5;
 11     private static Method m0;
 12     
 13     public $Proxy0(final InvocationHandler invocationHandler) {
 14         super(invocationHandler);
 15     }
 16     
 17     public final boolean equals(final Object o) {
 18         try {
 19             return (boolean)super.h.invoke(this, $Proxy0.m1, new Object[] { o });
 20         }
 21         catch (Error | RuntimeException error) {
 22             throw;
 23         }
 24         catch (Throwable t) {
 25             throw new UndeclaredThrowableException(t);
 26         }
 27     }
 28     
 29     public final String getSex() {
 30         try {
 31             return (String)super.h.invoke(this, $Proxy0.m4, null);
 32         }
 33         catch (Error | RuntimeException error) {
 34             throw;
 35         }
 36         catch (Throwable t) {
 37             throw new UndeclaredThrowableException(t);
 38         }
 39     }
 40     
 41     public final String toString() {
 42         try {
 43             return (String)super.h.invoke(this, $Proxy0.m2, null);
 44         }
 45         catch (Error | RuntimeException error) {
 46             throw;
 47         }
 48         catch (Throwable t) {
 49             throw new UndeclaredThrowableException(t);
 50         }
 51     }
 52     
 53     public final void getStandardsOfChoosingSpouse() {
 54         try {
 55             super.h.invoke(this, $Proxy0.m3, null);
 56         }
 57         catch (Error | RuntimeException error) {
 58             throw;
 59         }
 60         catch (Throwable t) {
 61             throw new UndeclaredThrowableException(t);
 62         }
 63     }
 64     
 65     public final String getHeight() {
 66         try {
 67             return (String)super.h.invoke(this, $Proxy0.m5, null);
 68         }
 69         catch (Error | RuntimeException error) {
 70             throw;
 71         }
 72         catch (Throwable t) {
 73             throw new UndeclaredThrowableException(t);
 74         }
 75     }
 76     
 77     public final int hashCode() {
 78         try {
 79             return (int)super.h.invoke(this, $Proxy0.m0, null);
 80         }
 81         catch (Error | RuntimeException error) {
 82             throw;
 83         }
 84         catch (Throwable t) {
 85             throw new UndeclaredThrowableException(t);
 86         }
 87     }
 88     
 89     static {
 90         try {
 91             $Proxy0.m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
 92             $Proxy0.m4 = Class.forName("com.wjc.proxy.People").getMethod("getSex", (Class<?>[])new Class[0]);
 93             $Proxy0.m2 = Class.forName("java.lang.Object").getMethod("toString", (Class<?>[])new Class[0]);
 94             $Proxy0.m3 = Class.forName("com.wjc.proxy.People").getMethod("getStandardsOfChoosingSpouse", (Class<?>[])new Class[0]);
 95             $Proxy0.m5 = Class.forName("com.wjc.proxy.People").getMethod("getHeight", (Class<?>[])new Class[0]);
 96             $Proxy0.m0 = Class.forName("java.lang.Object").getMethod("hashCode", (Class<?>[])new Class[0]);
 97         }
 98         catch (NoSuchMethodException ex) {
 99             throw new NoSuchMethodError(ex.getMessage());
100         }
101         catch (ClassNotFoundException ex2) {
102             throw new NoClassDefFoundError(ex2.getMessage());
103         }
104     }
105 }

  

spring設計模式_代理模式