JDK動态代理
最近也在瘋狂的補基礎知識,是以寫這篇部落格為了友善以後自己檢視。
攔截器
- 由于動态代理一般都比較難了解,程式設計者會設計一個攔截器接口供開發者使用, 開發者隻要知道攔截器接口的方法、含義和作用即可,無須知道動态代理是怎麼實作的。 用 JDK 動态代理來實作一個攔截器的邏輯,為此先定義攔截器接口
import java.lang.reflect.Method; public interface Interceptor { /** * 當傳回為true時,則反射真實對象的方法; * 當傳回為false時,則調用around方法。 * @param proxy 代理對象 * @param target 真實對象 * @param method 方法 * @param args 運作方法參數 * @return */ public boolean before(Object proxy, Object target, Method method,Object[] args); /** * 在before方法傳回為false時,則調用around方法。 * @param proxy * @param target * @param method * @param args * @return */ public void around(Object proxy, Object target,Method method,Object[] args); /** * 在反射真實對象方法或者around方法執行之後,調用after方法 * @param proxy * @param target * @param method * @param args * @return */ public void after(Object proxy, Object target,Method method,Object[] args); }
- 建立這個Interceptor的實作類-----MyInterceptor
package com.yl.interceptor; import java.lang.reflect.Method; /** * 攔截器實作類 */ public class Mylnterceptor implements Interceptor{ @Override public boolean before(Object proxy, Object target, Method method, Object[] args) { System.out.println("反射方法前邏輯---判斷使用者是否處于登入狀态---使用者未登入,操作攔截"); return false; //不反射被代理對象原有方法 } @Override public void around(Object proxy, Object target, Method method, Object[] args) { System.out.println("取代了被代理對象的方法---頁面轉發為指定界面,比如登入界面"); } @Override public void after(Object proxy, Object target, Method method, Object[] args) { System.out.println("反射方法後邏輯---記錄本次異常操作"); } }
它實作了所有的 Interceptor 接口方法,使用JDK動态代理,就可以實作這些方法在适當時的調用邏輯
- 在JDK動态代理中使用攔截器以及test用例
這裡有兩個屬性,一個是target,它是真實對象;另一個是字元串interceptorClass,它是一個攔截器的權限的類名。這裡解釋一下代碼執行的步驟:package com.yl.interceptor; import com.yl.jdk.HelloWorld; import com.yl.jdk.HelloWorldImpl; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 在JDK動态代理中使用攔截器 */ public class InterceptorJdkProxy implements InvocationHandler { private Object target = null; //真實對象 private String interceptorClass = null; //攔截器全限定名 public InterceptorJdkProxy(Object target, String interceptorClass) { this.target = target; this.interceptorClass = interceptorClass; } /** * 綁定委托對象并傳回一個【代理占位】 * @param target 真實對象 * @param interceptorClass * @return 代理對象【占位】 */ public static Object bind(Object target,String interceptorClass) { //取得代理對象 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InterceptorJdkProxy(target,interceptorClass)); } /** * 通過代理對象調用方法,首先進入這個方法 * @param proxy 代理對象 * @param method 方法,被調用方法 * @param args 方法的參數 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (interceptorClass == null) { //沒有設定攔截器則直接反射原有方法 return method.invoke(target,args); } Object result = null; //通過反射生成攔截器 Interceptor interceptor = (Interceptor) Class.forName(interceptorClass).newInstance(); //調用前置方法 if (interceptor.before(proxy,target,method,args)) { //傳回true,反射原有對象的方法 result = method.invoke(target,args); }else { //傳回false,執行around方法 interceptor.around(proxy,target,method,args); } //調用後置方法 interceptor.after(proxy,target,method,args); return result; } public static void main(String[] args) { //注冊攔截器 HelloWorld proxy = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(), "com.yl.interceptor.Mylnterceptor"); //不注冊攔截器 HelloWorld proxy2 = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(),null); /** * 結果 * 反射方法前邏輯---判斷使用者是否處于登入狀态---使用者未登入,操作攔截 * 取代了被代理對象的方法---頁面轉發為指定界面,比如登入界面 * 反射方法後邏輯---記錄本次異常操作 */ proxy.sayHelloWorld(); /** * 結果 * Hello World ! */ proxy2.sayHelloWorld(); } }
第 1 步,在 bind 方法中用 JDK 動态代理綁定了一個對象,然後傳回代理對象。 第 2 步, 如果沒有設定攔截器, 則直接反射真實對象的方法,然後結束,否則進行第 3 步。 第 3 步,通過反射生成攔截器,并準備使用它。 第 4 步,調用攔截器的 before 方法,如果傳回為 true,反射原來的方法;否則運作攔 截器的 around 方法。 第 5 步,調用攔截器的 after 方法。 第 6 步,傳回結果。
- HelloWorld接口
/** * JDK動态代理:必須借助一個接口才能産生代理對象,是以必須先定義接口。 */ public interface HelloWorld { public void sayHelloWorld(); }
- 提供HelloWorld的實作類來實作接口
/** * 提供HelloWorld的實作類來實作接口 */ public class HelloWorldImpl implements HelloWorld{ @Override public void sayHelloWorld() { System.out.println("Hello World !"); } }