標籤:
1. 核心類&介面
在Java的java.lang.reflect包下提供一個Proxy類和一個InvocationHandler介面,通過使用這個類和介面可以產生jdk動態代理類或動態代理對象。
Proxy是所有動態代理類的父類,它提供了兩個靜態方法來建立動態代理類和動態代理對象,如下:
? static Class<?>getProxyClass(ClassLoader loader,Class<?>... interfaces)
? static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
getProxyClass返回代理類的 java.lang.Class 對象,並向其提供類載入器和介面數組。newProxyInstance返回一個指定介面的代理類執行個體,該介面可以將方法調用轉寄到指定的調用處理常式,執行代理對象的每個方法時都會被替換執行InvocationHandler對象的Invoke方法。實際上,即使採用第一種方式擷取了一個動態代理類之後,當程式需要通過該代理類來建立對象時一樣需要傳入一個InvocationHandler對象。也就是說,系統產生的每個代理對象都有一個與之關聯的InvocationHandler對象。
從上面的兩個方法的參數可以看出,只有給我一個(或多個)介面,我們就可以產生實現了這個(或多個)介面的代理類和代理對象。
2. 兩種方式組建代理程式對象
下面我們就用上面提到兩種方式,分別來產生一個介面(Person)的代理對象。
2.1 介面Person
package com.tgb.reflect;/** * 目標介面 * * @author wangzhipeng * */public interface Person {public void walk();public void sayHello();}
2.2 構造一個InvocationHandler類
package com.tgb.reflect;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class MyInvocationHandler implements InvocationHandler {/** * 執行代理對象的所有方法時都會被替換成執行如下的invoke方法 * * proxy :代表動態代理對象; method:代表正在執行的方法 ;args :代表執行代理對象方法時傳入的實參 */@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// TODO Auto-generated method stubSystem.out.println("正在執行方法:" + method.getName());if (args != null) {System.out.println("下面是執行方法時傳入的實參:");for (Object object : args) {System.out.println(object);}} else {System.out.println("該方法調用無實參!");}return null;}}
2.3 方式一:利用getProxyClass組建代理程式對象
package com.tgb.reflect;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;/** * 利用getProxyClass組建代理程式對象 * * @author wangzhipeng * */public class TestReflectProxy {@SuppressWarnings("unchecked")public static void main(String[] args) throws Exception {// 1、建立一個InvocationHandler對象InvocationHandler myInvocationHandler = new MyInvocationHandler();// 2、建立Person介面的一個代理類(擷取代理類的位元組碼)Class proxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), new Class[] { Person.class });// 3、根據代理類的位元組碼拿到它的參數為InvocationHandler類型的構造器Constructor constructor = proxyClass.getConstructor(new Class[] { InvocationHandler.class });// 4、根據構造器建立代理對象Person person = (Person) constructor.newInstance(myInvocationHandler);// 5、調用代理對象的方法person.walk();person.sayHello();/** * 輸出結果如下: * * 正在執行方法:walk 該方法調用無實參! * * 正在執行方法:sayHello 該方法調用無實參! */}}
2.4 方式二:利用newProxyInstance組建代理程式對象
package com.tgb.reflect;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;/** * 利用newProxyInstance組建代理程式對象 * * @author wangzhipeng * */public class TestReflectProxy2 {public static void main(String[] args) {// 1、建立一個InvocationHandler對象InvocationHandler myInvocationHandler = new MyInvocationHandler();// 2、利用Proxy類的靜態方法newProxyInstance直接產生Person介面的代理對象Person person = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[] { Person.class }, myInvocationHandler);// 3、調用代理對象的方法person.walk();person.sayHello();/** * 輸出結果如下: * * 正在執行方法:walk 該方法調用無實參! * * 正在執行方法:sayHello 該方法調用無實參! */}}
3. 動態代理與aop
下面我們在上面例子的基礎上再擴充一小步,類比以下aop思想原理。其實,非常簡單,上面已經提到了,執行代理對象的每個方法時都被替換執行InvocationHandler對象的Invoke方法。所以我們只需要在Invoke方法中的“反射執行目標方法(method.invoke(target,args))“的前後加入我們增強方法即可。執行個體代碼如下:
3.1 目標介面Person
package com.tgb.reflect.aop;/** * 目標介面 * * @author wangzhipeng * */public interface Person {public void walk();public void sayHello();}
3.2 目標類ZhanSan
package com.tgb.reflect.aop;/** * 目標類(實現了Person介面) * * @author wangzhipeng * */public class ZhanSan implements Person {@Overridepublic void sayHello() {System.out.println("我是張三---->sayHello");}@Overridepublic void walk() {System.out.println("我是張三---->walk");}}
3.3 增強類Extend
package com.tgb.reflect.aop;/** * 增強類 * * @author wangzhipeng * */public class Extend {/** * 增強方法1 */public void ExtendMethod1() {System.out.println("我是增強方法一");}/** * 增強方法2 */public void ExtendMethod2() {System.out.println("我是增強方法二");}}
3.4 InvocationHandler類MyInvocationHandler
package com.tgb.reflect.aop;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class MyInvocationHandler implements InvocationHandler {// 目標對象(需要被代理的對象)private Object target;public void setTarget(Object target) {this.target = target;}/** * 執行代理對象的所有方法時都會被替換成執行如下的invoke方法 */@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 執行個體化一個增強類Extend extend = new Extend();// 執行增強方法1(類比spring前置增強)extend.ExtendMethod1();Object result = method.invoke(target, args);// 【執行目標方法】// 執行增強方法2(類比spring後置增強)extend.ExtendMethod2();return result;}}
3.5 代理產生工廠MyProxyFactory
package com.tgb.reflect.aop;import java.lang.reflect.Proxy;/** * 組建代理程式的工廠 * * @author wangzhipeng * */public class MyProxyFactory {/* * 擷取一個目標對象(目標類必須實現介面)的代理對象 */public static Object getProxy(Object target) {// 執行個體化一個InvocationHandler類,並傳入目標對象MyInvocationHandler myInvocationHandler = new MyInvocationHandler();myInvocationHandler.setTarget(target);// 組建代理程式對象Object proxyObject = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), myInvocationHandler);return proxyObject;}}
3.6 測試類別Test
package com.tgb.reflect.aop;/** * 測試類別 * * @author wangzhipeng * */public class Test {public static void main(String[] args) {// 建立一個原始的ZhanSan(實現了Person介面)對象作為TargetPerson zhanSan = new ZhanSan();// 利用代理工廠產生zhansan對象(Target)的代理對象Person proxyZhanSan = (Person) MyProxyFactory.getProxy(zhanSan);// 執行代理對象的方法(會執行織入的增強類(Extend)的兩個增強方法)proxyZhanSan.walk();proxyZhanSan.sayHello();}}
3.7 結果如下
4. 總結
Proxy類主要方法有四個(如),jdk動態代理主要是利用Proxy類的getProxyClass和newProxyInstance方法產生介面的動態代理對象,並將執行代理對象的每個方法時都被替換執行InvocationHandler對象的Invoke方法。這為Spring的aop打好了基礎。此外,實際應用中,我們一般不會單純直接產生一個(或多個)介面的代理對象,而是產生某個介面實作類別(目標類)的代理對象。
實際上普通的java編程中我們很少用到動態代理,它最大的魅力在於編寫架構或底層基礎代碼。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
Java反射—運用反射產生jdk動態代理