前言java
代理是什麼spring
事故現場:我家的寵物今天生病了,而我又沒有相關的醫學知識,因此我只讓個人寵物多喝熱水嗎?ide
結果顯然是不行的,因此我須要去找寵物醫生這些更專業的人來幫個人寵物治病。學習
這個時候,代理就出現了,而寵物醫生就是代理,而我就是目標對象。測試
總結起來就是代理代替目標對象執行相關操做,便是對目標對象的一種功能擴展。this
使用代理模式的條件spa
一、兩個角色:執行者,被代理對象代理
二、注重過程,必需要作,被代理的對象沒時間作或者不想作,不專業code
三、執行者必須拿到被代理對象的我的資料對象
1.靜態代理
代碼實現:
/** * 我和寵物醫生都是人,都有治療技能,可是寵物醫生比我更專業 */ interface IPerson{ void treat(Pet pet); //治療技能 } /** * 寵物類 */ class Pet{ private String name; public Pet(String name){ this.name = name; } public String getName() { return name; } } /** * 目標對象實現」IPerson「接口 */ class Self implements IPerson{ private Pet pet; public Self(Pet pet){ this.pet = pet; } public void treat(Pet pet){ System.out.println(pet.getName() + ",你要多喝點水"); } } /** * 代理對象與目標對象實現同一接口 */ class PetDoctor implements IPerson{ //接收目標對象 private IPerson targetObj; public PetDoctor(IPerson targetObj){ this.targetObj = targetObj; } @Override public void treat(Pet pet) { System.out.println("對" + pet.getName() + "進行檢查"); targetObj.treat(pet); System.out.println("對" + pet.getName() + "進行治療"); } }
代碼測試:
public static void main(String[] args){ //個人寵物 Pet pet = new Pet("多多"); //目標對象 IPerson target = new Self(pet); //代理對象 IPerson proxy = new PetDoctor(target); proxy.treat(pet); }
運行結果:
寵物醫生對多多進行檢查
我對多多說,你要多喝點水
寵物醫生對多多進行治療
結果很明顯,醫生比我更專業,我只會讓個人寵物喝水,但醫生會先檢查再進行專業的治療,因此說代理是讓更專業的對象幫你作事。
2.動態代理
動態代理又分爲jdk動態代理和cglib動態代理,二者的區別是jdk動態代理的實現是基於接口,而cglib動態代理是基於繼承,但二者作的是同一件事,那就是字節碼重組。
基本流程都是根據目標對象的資料,經過反射獲取該對象的信息,而後根據信息按照特定的寫法重寫一個java類,再進行編譯並動態加載到JVM中運行,因此說動態代理在底層其實就是實現了字節碼重組。
jdk動態代理實例演示
Person接口
//定義Person接口,技能是煮飯 public interface Person { void cook(); }
我本身,也就是被代理的對象,但我只會作可樂雞翅
public class Oneself implements Person { @Override public void cook() { System.out.println("我會作可樂雞翅"); } }
動態代理類,也是一個廚師,由於初始對於作菜比我更專業
public class Kitchener implements InvocationHandler{ //須要代理的目標對象 private Object object; public Kitchener(Object object){ this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("我會作糖醋排骨"); method.invoke(object,args); //這是我會作的,其他兩樣是代理對象初始會作的 System.out.println("我會作九轉大腸"); return null; } }
測試代碼
public class TestJdk { public static void main(String[] args){ //建立目標代理對象 Oneself oneself = new Oneself(); InvocationHandler kitchener = new Kitchener(oneself); /* * 經過Proxy的newProxyInstance方法來建立咱們的代理對象,作的就是字節碼重組的工做,新生成一個java類在編譯再加載到JVM運行 * 第一個參數是類加載器 * 第二個參數是咱們這裏爲代理對象提供的接口,也就是代理對象所實現的接口,因此說在jdk動態代理中被代理對象須要實現一個接口 * 第三個參數handler, 咱們這裏將這個代理對象關聯到了上方的 InvocationHandler 這個對象上 */ Person proxy = (Person) Proxy.newProxyInstance(kitchener.getClass().getClassLoader(), oneself.getClass().getInterfaces(), kitchener); System.out.println(proxy.getClass()); // (1) proxy.cook(); } }
測試結果
class com.sun.proxy.$Proxy0 //(2)
我會作糖醋排骨
我會作可樂雞翅
我會作九轉大腸
能夠看到(1)行代碼打印出來的是一個代理類,而代理對象經過生成java類再編譯加載運行對用戶來講是無感知的,咱們只知道返回回來的是一個代理對象,而後由代理對象去幫咱們作事。
而cglib代理的實現原理也是同樣的,只不過一個是基於接口,一個是基於繼承,原理都是經過反射獲取對象信息再根據對象信息建立java類編譯加載運行,因此cglib暫時就不展開了,後期能夠本身手寫一個動態加深理解。
學習了動態代理後,在本人的工做中是沒使用過的,但倒是瞭解spring的AOP實現的必要基礎,由於spring的AOP實現就是基於動態代理實現的。