一、代理的概念
動態代理技術是整個java技術中最重要的一個技術,它是學習java架構的基礎,不會動態代理技術,那麼在學習Spring這些架構時是學不明白的。
動態代理技術就是用來產生一個對象的代理對象的。在開發中為什麼需要為一個對象產生代理對象呢。
舉一個現實生活中的例子:歌星或者明星都有一個自己的經紀人,這個經紀人就是他們的代理人,當我們需要找明星表演時,不能直接找到該明星,只能是找明星的代理人。比如劉德華在現實生活中非常有名,會唱歌,會跳舞,會拍戲,劉德華在沒有出名之前,我們可以直接找他唱歌,跳舞,拍戲,劉德華出名之後,他乾的第一件事就是找一個經紀人,這個經紀人就是劉德華的代理人(代理),當我們需要找劉德華表演時,不能直接找到劉德華了(劉德華說,你找我代理人商談具體事宜吧!),只能是找劉德華的代理人,因此劉德華這個代理人存在的價值就是攔截我們對劉德華的直接存取。
這個現實中的例子和我們在開發中是一樣的,我們在開發中之所以要產生一個對象的代理對象,主要用於攔截對真實業務對象的訪問。那麼代理對象應該具有什麼方法呢。代理對象應該具有和目標對象相同的方法
所以在這裡明確代理對象的兩個概念:
1、代理對象存在的價值主要用於攔截對真實業務對象的訪問。
2、代理對象應該具有和目標對象(真實業務對象)相同的方法。劉德華(真實業務對象)會唱歌,會跳舞,會拍戲,我們現在不能直接找他唱歌,跳舞,拍戲了,只能找他的代理人(代理對象)唱歌,跳舞,拍戲,一個人要想成為劉德華的代理人,那麼他必須具有和劉德華一樣的行為(會唱歌,會跳舞,會拍戲),劉德華有什麼方法,他(代理人)就要有什麼方法,我們找劉德華的代理人唱歌,跳舞,拍戲,但是代理人不是真的懂得唱歌,跳舞,拍戲的,真正懂得唱歌,跳舞,拍戲的是劉德華,在現實中的例子就是我們要找劉德華唱歌,跳舞,拍戲,那麼只能先找他的經紀人,交錢給他的經紀人,然後經紀人再讓劉德華去唱歌,跳舞,拍戲。 二、java中的代理 2.1、"java.lang.reflect.Proxy"類介紹
現在要產生某一個對象的代理對象,這個代理對象通常也要編寫一個類來產生,所以首先要編寫用於組建代理程式對象的類。在java中如何用程式去產生一個對象的代理對象呢,java在JDK1.5之後提供了一個"java.lang.reflect.Proxy"類,通過"Proxy"類提供的一個newProxyInstance方法用來建立一個對象的代理對象,如下所示:
1 static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
newProxyInstance方法用來返回一個代理對象,這個方法總共有3個參數,ClassLoader loader用來指明組建代理程式對象使用哪個類裝載器,Class<?>[] interfaces用來指明產生哪個對象的代理對象,通過介面指定,InvocationHandler h用來指明產生的這個代理對象要做什麼事情。所以我們只需要調用newProxyInstance方法就可以得到某一個對象的代理對象了。 2.2、編寫組建代理程式對象的類
在java中規定,要想產生一個對象的代理對象,那麼這個對象必須要有一個介面,所以我們第一步就是設計這個對象的介面,在介面中定義這個對象所具有的行為(方法)
1、定義對象的行為介面
1 package cn.gacl.proxy; 2 3 /** 4 * @ClassName: Person 5 * @Description: 定義對象的行為 6 * @author: 孤傲蒼狼 7 * @date: 2014-9-14 下午9:44:22 8 * 9 */ 10 public interface Person {11 12 /**13 * @Method: sing14 * @Description: 唱歌15 * @Anthor:孤傲蒼狼16 *17 * @param name18 * @return19 */ 20 String sing(String name);21 /**22 * @Method: sing23 * @Description: 跳舞24 * @Anthor:孤傲蒼狼25 *26 * @param name27 * @return28 */ 29 String dance(String name);30 }
2、定義目標業務對象類
1 package cn.gacl.proxy; 2 3 /** 4 * @ClassName: LiuDeHua 5 * @Description: 劉德華實現Person介面,那麼劉德華會唱歌和跳舞了 6 * @author: 孤傲蒼狼 7 * @date: 2014-9-14 下午9:22:24 8 * 9 */ 10 public class LiuDeHua implements Person {11 12 public String sing(String name){13 System.out.println("劉德華唱"+name+"歌。。");14 return "歌唱完了,謝謝大家。";15 }16 17 public String dance(String name){18 System.out.println("劉德華跳"+name+"舞。。");19 return "舞跳完了,多謝各位觀眾。";20 }21 }
3、建立組建代理程式對象的代理類
1 package cn.gacl.proxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Proxy; 6 7 /** 8 * @ClassName: LiuDeHuaProxy 9 * @Description: 這個代理類負責產生劉德華的代理人10 * @author: 孤傲蒼狼11 * @date: 2014-9-14 下午9:50:0212 *13 */ 14 public class LiuDeHuaProxy {15 16 //設計一個類變數記住代理類要代理的目標對象17 private Person ldh = new LiuDeHua();18 19 /**20 * 設計一個方法組建代理程式對象21 * @Method: getProxy22 * @Description: 這個方法返回劉德華的代理對象:Person person = LiuDeHuaProxy.getProxy();//得到一個代理對象23 * @Anthor:孤傲蒼狼24 *25 * @return 某個對象的代理對象26 */ 27 public Person getProxy() {28 //使用Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)返回某個對象的代理對象29 return (Person) Proxy.newProxyInstance(LiuDeHuaProxy.class30 .getClassLoader(), ldh.getClass().getInterfaces(),31 new InvocationHandler() {32 /**33 * InvocationHandler介面只定義了一個invoke方法,因此對於這樣的介面,我們不用單獨去定義一個類來實現該介面,34 * 而是直接使用一個匿名內部類來實現該介面,new InvocationHandler() {}就是針對InvocationHandler介面的匿名實作類別35 */36 /**37 * 在invoke方法編碼指定返回的代理對象乾的工作38 * proxy : 把代理對象自己傳遞進來 39 * method:把代理對象當前調用的方法傳遞進來 40 * args:把方法參數傳遞進來41 * 42 * 當調用代理對象的person.sing("冰雨");或者 person.dance("江南style");方法時,43 * 實際上執行的都是invoke方法裡面的代碼,44 * 因此我們可以在invoke方法中使用method.getName()就可以知道當前調用的是代理對象的哪個方法45 */46 @Override47 public