JAVA學習之動態代理。本站提示廣大學習愛好者:(JAVA學習之動態代理)文章只能為提供參考,不一定能成為您想要的結果。以下是JAVA學習之動態代理正文
JDK1.6中的動態代理
在Java中Java.lang.reflect包下提供了一個Proxy類和一個InvocationHandler接口,通過使用這個類和接口可以生成一個動態代理對象。JDK提供的代理只能針對接口做代理
java.lang.reflect.Proxy 提供用於創建動態代理類和實例的靜態方法,它還是由這些方法創建的所有動態代理類的超類。
// 方法 1: 該方法用於獲取指定代理對象所關聯的調用處理器 public static InvocationHandler getInvocationHandler(Object proxy) // 方法 2:該方法用於獲取關聯於指定類裝載器和一組接口的動態代理類的類對象 public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) // 方法 3:該方法用於判斷指定類對象是否是一個動態代理類 public static boolean isProxyClass(Class<?> cl) // 方法 4:該方法用於為指定類裝載器、一組接口及調用處理器生成動態代理類實例 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
java.lang.reflect.InvocationHandler:調用處理器接口,自定義invokle方法,用於實現對於真正委托類的代理訪問。
/** 該方法負責集中處理動態代理類上的所有方法調用。 第一個參數既是代理類實例, 第二個參數是被調用的方法對象(反射中Method對象) 第三個參數是調用方法的參數列表。 調用處理器根據這三個參數進行預處理或分派到委托類實例上發射執行 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
使用Proxy類中的newProxyInstance方法創建代理對象
參數: loader - 定義代理類的類加載器 interfaces - 代理類要實現的接口列表 h - 指派方法調用的調用處理程序 返回: 一個帶有代理類的指定調用處理程序的代理實例,它由指定的類加載器定義,並實現指定的接口 public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException
實例
接口:
package com.jalja.org.base.poxy; public interface ArithmeticCalculator { int add(int i, int j); int sub(int i, int j); int mul(int i, int j); int div(int i, int j); }
實現類:
package com.jalja.org.base.poxy; public class ArithmeticCalculatorImpl implements ArithmeticCalculator { @Override public int add(int i, int j) { int result = i + j; System.out.println("add:"+result); return result; } @Override public int sub(int i, int j) { int result = i - j; System.out.println("sub:"+result); return result; } @Override public int mul(int i, int j) { int result = i * j; System.out.println("mul:"+result); return result; } @Override public int div(int i, int j) { int result = i / j; System.out.println("div:"+result); return result; } }
代理類及使用:
package com.jalja.org.base.poxy.test; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import com.jalja.org.base.poxy.ArithmeticCalculator; import com.jalja.org.base.poxy.ArithmeticCalculatorImpl; public class MyInvocationHandler implements InvocationHandler{ private Object target;//目標對象(對哪個對象做動態代理) public MyInvocationHandler(Object target) { this.target=target; } @Override /** * proxy - 在其上調用方法的代理實例 * method - 對應於在代理實例上調用的接口方法的 Method 實例。Method 對象的聲明類將是在其中聲明方法的接口,該接口可以是代理類賴以繼承方法的代理接口的超接口。 * args - 包含傳入代理實例上方法調用的參數值的對象數組,如果接口方法不使用參數,則為 null。基本類型的參數被包裝在適當基本包裝器類(如 java.lang.Integer 或 java.lang.Boolean)的實例中。 * return - 返回代理對象 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //obj - 從中調用底層方法的對象 //args - 用於方法調用的參數 //public Object invoke(Object obj, Object... args)throws IllegalAccessException, IllegalArgumentException,InvocationTargetException System.out.println(method.getName()+"方法前置。。。。。。。。。。。。。。。。"); Object result=method.invoke(target, args); System.out.println("method:"+method); System.out.println(method.getName()+"方法後置。。。。。。。。。。。。。。。。"); return result; } public static void main(String[] args) { /*參數: loader - 定義代理類的類加載器 interfaces - 代理類要實現的接口列表 h - 指派方法調用的調用處理程序 返回: 一個帶有代理類的指定調用處理程序的代理實例,它由指定的類加載器定義,並實現指定的接口 public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException*/ ArithmeticCalculator ac=new ArithmeticCalculatorImpl(); //Object proxy=Proxy.newProxyInstance(ac.getClass().getClassLoader(), ac.getClass().getInterfaces(), new MyInvocationHandler(ac)); ArithmeticCalculator proxy=(ArithmeticCalculator)Proxy.newProxyInstance( ac.getClass().getClassLoader(), ac.getClass().getInterfaces(), new MyInvocationHandler(ac)); proxy.add(10, 100); proxy.sub(20, 10); } }
Cglib動態代理
JDK的動態代理機制只能代理實現了接口的類,而不能實現接口的類就不能實現JDK的動態代理,cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現增強,但因為采用的是繼承,所以不能對final修飾的類進行代理。
Demo:
package com.jalja.org.base.poxy.Cglib; import java.lang.reflect.Method; import com.jalja.org.base.poxy.ArithmeticCalculatorImpl; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CglibProxy implements MethodInterceptor{ private Object target; /** * 創建代理對象 * @param target * @return */ public Object getInstance(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); // 回調方法 enhancer.setCallback(this); // 創建代理對象 return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("前置代理"); //通過代理類調用父類中的方法 Object result = proxy.invokeSuper(obj, args); System.out.println("後置代理"); return result; } public static void main(String[] args) { CglibProxy cglib=new CglibProxy(); ArithmeticCalculatorImpl bookCglib=(ArithmeticCalculatorImpl)cglib.getInstance(new ArithmeticCalculatorImpl()); bookCglib.add(10, 30); } }
CGLib創建的動態代理對象性能比JDK創建的動態代理對象的性能高不少,但是CGLib在創建代理對象時所花費的時間卻比JDK多得多,所以對於單例的對象,因為無需頻繁創建對象,用CGLib合適,反之,使用JDK方式要更為合適一些。