1,staic Class getProxyClass(ClassLoader loader,Class .... interfaces):建立一個動態代理類所對應的Class對象,該代理類將實現interfaces所指定的多個接口。loader參數指定生成的動態代理類的類加載器。java
2,static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h);直接建立一個動態代理對象,該代理對象的實現類實現了interfaces指定的系列接口,執行代理對象的每一個方法時都會被替換執行InvocationHandler對象的invoke方法。編程
1,代理接口框架
package www.com.lining.test1; public interface Person { void walk(); void sayHello(String name); }
2,實現類ide
package www.com.lining.test1; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvokationHandler implements InvocationHandler { /** * 執行動態代理對象的全部方法時,都會被替換成invoke方法</br> * proxy:表明代理的對象 mothod:正在執行的方法 args:調用目標方法時的實參 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("-----正在執行的方法:" + method); if (args != null) { System.out.println("下面是執行該方法時傳入的實參爲:"); for (Object val : args) { System.out.println(val); } } else { System.out.println("調用該方法沒有實參!"); } return null; } }
3,測試類測試
package www.com.lining.test1; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class ProxyTest { public static void main(String[] args) { // 建立一個InvocationHandler對象 InvocationHandler handler = new MyInvokationHandler(); // 使用指定的InvocationHandler來生成一個動態代理對象 Person p = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[] { Person.class }, handler);// 得到代理接口的加載器,建立接口的class對象,代理接口的實現類對象。 // 調用動態代理對象的walk()和sayhello()方法 p.walk(); p.sayHello("孫悟空"); } }
4,運行結果this
-----正在執行的方法:public abstract void www.com.lining.test1.Person.walk() 調用該方法沒有實參! -----正在執行的方法:public abstract void www.com.lining.test1.Person.sayHello(java.lang.String) 下面是執行該方法時傳入的實參爲: 孫悟空
實際上,在廣泛的編程過程當中,確實無需使用動態代理,可是在編寫框架或底層基礎代碼時,動態代理的做用就很是大了。編碼
1,咱們先提供一個Dog接口,定義兩個方法就好。代理
package www.com.lining.test1; /** * 要被代理的對象 * * @author YOONA * */ public interface Dog { void info(); void eat(); }
2,這裏使用的是AOP代理不是jdk代理,因此咱們不要直接使用Proxy爲給接口建立動態代理對象,而是爲該接口提供實現類code
package www.com.lining.test1; public class GunDog implements Dog { @Override public void info() { System.out.println("你是一隻獵狗"); } @Override public void eat() { System.out.println("你吃shi的很香"); } }
3,這裏咱們須要提供一個前面提起的一個代碼塊須要被重複使用,咱們不要複製粘貼,而是使用代理來調用不一樣方法可是是同一個代碼塊的方法。對象
package www.com.lining.test1; public class DogUtil { public void method1() { System.out.println("=====模擬第一個通用方法======"); } public void method2() { System.out.println("=====模擬第二個通用方法======"); } }
4,咱們藉助Proxy的InvocationHandler就能夠實現調用Dog接口裏的方法,這時程序就會自動調用相同的代碼塊method1,method2。這裏的做用就是當使用代理對象時就會執行該類中的invoke方法。執行動態代理對象的全部方法時,都會被替換成執行Invoke方法。
package www.com.lining.test1; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvokationHandler2 implements InvocationHandler { private Object target; public void setTarget(Object t) { this.target = t; } //重寫Invoke方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { DogUtil du = new DogUtil(); du.method1(); Object res = method.invoke(target, args); du.method2(); return null; } }
5,根據上面的程序咱們能夠定義target爲被代理的實例,這裏咱們創建一個代理該對象的工廠。
package www.com.lining.test1; import java.lang.reflect.Proxy; public class MyProxyFactory { public static Object getProxy(Object t) { // 建立一個實現InvocationHandler的類對象 MyInvokationHandler2 handler2 = new MyInvokationHandler2(); // 爲MyInvokationHandler2設置setTarget; handler2.setTarget(t); return Proxy.newProxyInstance(GunDog.class.getClassLoader(), t.getClass().getInterfaces(), handler2); } }
6,調用MyProxyFactory對象的getProxy(代理實例)方法,來建立動態代理對象。
package www.com.lining.test1; public class TestAOP { public static void main(String[] args) { Dog t = new GunDog(); Dog d = (Dog) MyProxyFactory.getProxy(t); d.info(); d.eat(); } }
7,輸出結果
=====模擬第一個通用方法====== 你是一隻獵狗 =====模擬第二個通用方法====== =====模擬第一個通用方法====== 你shi吃的很香 =====模擬第二個通用方法======
總結:
1,上面的動態代理工廠提供了一個getProxy()方法,該方法爲target對象生成一個動態代理對象,這個代理對象與target實例實現了相同的接口,因此具備相同的public方法,也就是說動態代理對象能夠當成target對象使用。當程序調用動態代理對象的指定方法時,實際上將變成執行MyInvocationHandler對象的invoke方法。執行步驟以下:
從上面的過程當中咱們能夠看出:當使用動態代理對象來替代target對象時,代理對象的方法就實現了前面的要求--程序執行info,eat方法時既能插入method一、method2通用方法,但GunDog的方法中又沒有以硬編碼方式調用method一、method2通用方法。
2,執行步驟: 程序執行dog的info和eat方法時,實際執行的是DogUtil的方法method1,再執行target對象的info和eat,最後執行DogUtil的method2方法。(AOP面向切面編程)
3,AOP代理方法示意圖: