歡迎您光臨本站 註冊首頁

Java使用JDK與Cglib動態代理技術統一管理日誌記錄

←手機掃碼閱讀     retouched @ 2020-05-09 , reply:0

Java中動態代理主要有JDK和CGLIB兩種方式。
區別主要是jdk是代理接口,而cglib是代理類。
優點:這種方式已經解決我們前面所有日記需要的問題。非常的靈活。而且可以方便的在後期進行維護和升級。
缺點:當然使用jdk動態代理,必需要有接口。如果沒有接口。就無法使用jdk動態代理技術。
計算接口 Calculate.java
public interface Calculate { /** * 加法運算 * @param num1 參數 1 * @param num2 參數 2 * @return */ public int add(int num1, int num2); /** * 加法運算 * @param num1 參數 1 * @param num2 參數 2 * @param num3 參數 3 * @return */ public int add(int num1, int num2, int num3); /** * 除法運算 * @param num1 參數 1 * @param num2 參數 2 * @return */ public int div(int num1, int num2); }
實現計算接口中的方法 CalculateImpl.java
/** * 實現計算接口中的方法 * Created by YongXin Xue on 2020/05/05 11:29 */ public class CalculateImpl implements Calculate { @Override public int add(int num1, int num2) { // 記錄當前操作,及運算參數 LogUtils.logBefore("add", num1, num2); int result = num1 + num2; return result; } @Override public int add(int num1, int num2, int num3) { // 記錄當前操作,及運算參數 LogUtils.logBefore("add", num1, num2, num3); int result = num1 + num2 + num3; return result; } @Override public int div(int num1, int num2) { // 記錄當前操作,及運算參數 LogUtils.logBefore("div", num1, num2); int result = 0; try { result = num1 / num2; // 記錄運算結果 LogUtils.logAfterReturning("div", result); }catch (Exception e){ // 記錄異常信息 LogUtils.logAfterThrowing("div", e); } return result; } }
記錄日誌工具類 LogUtils.java
/** * 記錄日誌工具類 * Created by YongXin Xue on 2020/05/05 11:38 */ public class LogUtils { /** * 記錄前置的日誌操作 * @param method 當前運算操作 * @param args 當前運算參數 */ public static void logBefore(String method, Object ... args){ System.out.println("操作運算是 : " + method + " 參數是 : " + Arrays.asList(args)); } /** * 返回日誌操作 * @param method 當前方法 * @param result 當前操作返回值 */ public static void logAfterReturning(String method, Object result){ System.out.println("當前操作運算時 : " + method + " 返回值是 : " + result); } /** * 當前操作產生的異常 * @param method 當前操作 * @param e 發生的異常 */ public static void logAfterThrowing(String method, Exception e){ System.out.println("當前運算時 : " + method + " 發生的異常是 : " + e); } }
JDK 動態代理的工廠類 JDKProxyFactory.java
/** * JDK 動態代理的工廠 * Created by YongXin Xue on 2020/05/05 13:02 */ public class JDKProxyFactory { /** * 通過 JDK 底層自帶的 JDK 動態代理技術解決日誌需求問題 * @param target * @return */ public static Object createJDKProxy(Object target){ /** * Proxy 是Jdk中自帶的一個工具類(反射包下,屬於反射的功能). * Proxy類的作用: 它可以幫我們創建代理類或實例 * 方法newProxyInstance()說明: 創建代理對象實例 * 第一個參數是: 目標對象的類加載器 * 第二個參數是: 目標對象實現的所有接口 * 第三個參數是: InvocationHandler 接口的實例 * InvocationHandler 接口的實現類可以對代理的目標對象方法進行增強操作. * 代理的目標對象 ===>>> 需要額外增加功能的類(對象實例) * 增強操作 ===>>> 給原來功能添加的額外功能叫增強操作 ( 日記就是增強操作 ) */ return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { // 匿名內部類 /** * invoke 方法是 InvocationHandler 接口中唯一的方法 * 代理對象每次調用方法時,都會執行 invoke() 方法 , 所有的增強操作都需要在invoke()方法中完成 * @param proxy 代理對象實例 * @param method 代理調用的方法的反射 Method 對象實例 * @param args 調用代理方法時傳遞進來的參數 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理調用了 invoke 方法 "); System.out.println(method); //打印方法信息 System.out.println(Arrays.asList(args)); //打印參數信息 // invoke() 方法執行代理對象的(加法 / 除法 / 增強日誌)操作 Object result = null; LogUtils.logBefore(method.getName(), args); try { // 1. 返回值是 method 方法調用時的返回值 result = method.invoke(target, args); // 2. 增強操作 LogUtils.logAfterReturning(method.getName(), result); }catch (Exception e){ LogUtils.logAfterThrowing(method.getName(), e); } // invoke() 返回代理方法的返回值 return result; } }); } // 測試代碼 public static void main(String[] args) { // 目標對象 Calculate target = new CalculateImpl(); // 創建 Calculate 的代理對象實例 Calculate calculateProxy = (Calculate) createJDKProxy(target ); // jdk動態代理對象實例和目標對象實例 同宗同族 ( 他們都實現了相同的接口 ) System.out.println(calculateProxy instanceof Calculate); System.out.println(target instanceof Calculate); System.out.println( "代理方法的結果是 : " + calculateProxy.div(100,20) ); // jdk動態代理創建出來的代理對象實例 是 目標對象 接口的一個實現類 // 這個代理對象 和 目標對象類沒有父子關係 ( 只能用接口接收代理對象 ) } }
使用 Cglib 代理
Jdk動態代理是通過實現目標對象所有接口產生一個代理對象實例從而解決問題. 如果目標對象沒有接口.則可以使用Cglib動態代理技術. Cglib動態代理技術對目標對象有沒有實現接口,沒有要求. Cglib動態代理技術,是通過拷貝然後修改目標對象的類的字節碼來產生一個代理對象 而且這個Cglib產生的代理對象實例 是 目標對象的一個子類.
IA 接口 IA.java
public interface IA { public String show(String start); }
IA 實現類 IAImpl.java
public class IAImpl implements IA { @Override public String show(String start) { System.out.println(start + "開始表演!"); return start + "表演的不錯!!"; } }
使用 Cglib 代理 CglibProxyFactory.java
/** * 使用 Cglib 代理 * Created by YongXin Xue on 2020/05/05 15:03 */ public class CglibProxyFactory { public static Object createCglibProxy(Object target){ // 是 Cglib 用於創建代理對象的增強工具類 Enhancer enhancer = new Enhancer(); // Cglib需要對目標對象的Class字節碼進行修改. // Cglib產生的代理對象實例.是目標對象的子類 enhancer.setSuperclass(target.getClass()); // 只要是代理都會對原來的內容進行增強操作 ( 增強就是在原有功能上 額外添加的功能 ) // setCallback() 設置用於增強 操作的實現類( MethodInterceptor對代理方法進行攔截 ) // 每次只要調用Cglib代理的方法,都會執行 MethodInterceptor 接口中 intercept() 方法 enhancer.setCallback(new MethodInterceptor() { /** * intercept() 方法 跟 JDK 代理中的 InvocationHandler接口中 invoke() 功能完全一樣 * @param proxy Cglib代理對象實例 * @param method 調用方法的反射對象實例 * @param args 調用方法時傳遞的參數 * @param methodProxy 代理方法的method代理對象 * @return 是代理對象方法的返回值. * @throws Throwable */ @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object result = null; try { LogUtils.logBefore(method.getName(), args); // 調用目標方法 [加 / 減 / 乘 / 除 / 或具體方法] result = method.invoke(target, args); // 執行增強代碼 LogUtils.logAfterReturning(method.getName(), args); }catch (Exception e){ e.printStackTrace(); LogUtils.logAfterThrowing(method.getName(), e); } return result; } }); // 創建 Cglib 代理對象實例 return enhancer.create(); } //測試 public static void main(String[] args) { // 目標對象 Calculate calculate = new CalculateImpl(); // 創建代理對象實例 Calculate cglibProxy = (Calculate) createCglibProxy(calculate); // 調用代理方法式會執行 MethodInterceptor 接口中 intercept() 方法 int result = cglibProxy.div(120, 0); // Cglib 代理 是目標子類執行 MethodInterceptor 接口中 intercept() 方法 System.out.println(cglibProxy instanceof Calculate); } }
優點:在沒有接口的情況下,同樣可以實現代理的效果。
缺點:同樣需要自己編碼實現代理全部過程。


[retouched ] Java使用JDK與Cglib動態代理技術統一管理日誌記錄已經有267次圍觀

http://coctec.com/docs/java/show-post-233397.html