這篇文章主要講解了Java如何使用JDK與Cglib動態(tài)代理技術(shù)統(tǒng)一管理日志記錄,內(nèi)容清晰明了,對此有興趣的小伙伴可以學(xué)習(xí)一下,相信大家閱讀完之后會有幫助。
站在用戶的角度思考問題,與客戶深入溝通,找到漢壽網(wǎng)站設(shè)計與漢壽網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗,讓設(shè)計與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個性化、用戶體驗好的作品,建站類型包括:成都網(wǎng)站設(shè)計、成都網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣、空間域名、虛擬空間、企業(yè)郵箱。業(yè)務(wù)覆蓋漢壽地區(qū)。
Java中動態(tài)代理主要有JDK和CGLIB兩種方式。
區(qū)別主要是jdk是代理接口,而cglib是代理類。
計算接口 Calculate.java
public interface Calculate { /** * 加法運算 * @param num1 參數(shù) 1 * @param num2 參數(shù) 2 * @return */ public int add(int num1, int num2); /** * 加法運算 * @param num1 參數(shù) 1 * @param num2 參數(shù) 2 * @param num3 參數(shù) 3 * @return */ public int add(int num1, int num2, int num3); /** * 除法運算 * @param num1 參數(shù) 1 * @param num2 參數(shù) 2 * @return */ public int div(int num1, int num2); }
實現(xiàn)計算接口中的方法 CalculateImpl.java
/** * 實現(xiàn)計算接口中的方法 * Created by YongXin Xue on 2020/05/05 11:29 */ public class CalculateImpl implements Calculate { @Override public int add(int num1, int num2) { // 記錄當(dāng)前操作,及運算參數(shù) LogUtils.logBefore("add", num1, num2); int result = num1 + num2; return result; } @Override public int add(int num1, int num2, int num3) { // 記錄當(dāng)前操作,及運算參數(shù) LogUtils.logBefore("add", num1, num2, num3); int result = num1 + num2 + num3; return result; } @Override public int div(int num1, int num2) { // 記錄當(dāng)前操作,及運算參數(shù) LogUtils.logBefore("div", num1, num2); int result = 0; try { result = num1 / num2; // 記錄運算結(jié)果 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 當(dāng)前運算操作 * @param args 當(dāng)前運算參數(shù) */ public static void logBefore(String method, Object ... args){ System.out.println("操作運算是 : " + method + " 參數(shù)是 : " + Arrays.asList(args)); } /** * 返回日志操作 * @param method 當(dāng)前方法 * @param result 當(dāng)前操作返回值 */ public static void logAfterReturning(String method, Object result){ System.out.println("當(dāng)前操作運算時 : " + method + " 返回值是 : " + result); } /** * 當(dāng)前操作產(chǎn)生的異常 * @param method 當(dāng)前操作 * @param e 發(fā)生的異常 */ public static void logAfterThrowing(String method, Exception e){ System.out.println("當(dāng)前運算時 : " + method + " 發(fā)生的異常是 : " + e); } }
JDK 動態(tài)代理的工廠類 JDKProxyFactory.java
/** * JDK 動態(tài)代理的工廠 * Created by YongXin Xue on 2020/05/05 13:02 */ public class JDKProxyFactory { /** * 通過 JDK 底層自帶的 JDK 動態(tài)代理技術(shù)解決日志需求問題 * @param target * @return */ public static Object createJDKProxy(Object target){ /** * Proxy 是Jdk中自帶的一個工具類(反射包下,屬于反射的功能). * Proxy類的作用: 它可以幫我們創(chuàng)建代理類或?qū)嵗? * 方法newProxyInstance()說明: 創(chuàng)建代理對象實例 * 第一個參數(shù)是: 目標(biāo)對象的類加載器 * 第二個參數(shù)是: 目標(biāo)對象實現(xiàn)的所有接口 * 第三個參數(shù)是: InvocationHandler 接口的實例 * InvocationHandler 接口的實現(xiàn)類可以對代理的目標(biāo)對象方法進行增強操作. * 代理的目標(biāo)對象 ===>>> 需要額外增加功能的類(對象實例) * 增強操作 ===>>> 給原來功能添加的額外功能叫增強操作 ( 日記就是增強操作 ) */ return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { // 匿名內(nèi)部類 /** * invoke 方法是 InvocationHandler 接口中唯一的方法 * 代理對象每次調(diào)用方法時,都會執(zhí)行 invoke() 方法 , 所有的增強操作都需要在invoke()方法中完成 * @param proxy 代理對象實例 * @param method 代理調(diào)用的方法的反射 Method 對象實例 * @param args 調(diào)用代理方法時傳遞進來的參數(shù) * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理調(diào)用了 invoke 方法 "); System.out.println(method); //打印方法信息 System.out.println(Arrays.asList(args)); //打印參數(shù)信息 // invoke() 方法執(zhí)行代理對象的(加法 / 除法 / 增強日志)操作 Object result = null; LogUtils.logBefore(method.getName(), args); try { // 1. 返回值是 method 方法調(diào)用時的返回值 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) { // 目標(biāo)對象 Calculate target = new CalculateImpl(); // 創(chuàng)建 Calculate 的代理對象實例 Calculate calculateProxy = (Calculate) createJDKProxy(target ); // jdk動態(tài)代理對象實例和目標(biāo)對象實例 同宗同族 ( 他們都實現(xiàn)了相同的接口 ) System.out.println(calculateProxy instanceof Calculate); System.out.println(target instanceof Calculate); System.out.println( "代理方法的結(jié)果是 : " + calculateProxy.div(100,20) ); // jdk動態(tài)代理創(chuàng)建出來的代理對象實例 是 目標(biāo)對象 接口的一個實現(xiàn)類 // 這個代理對象 和 目標(biāo)對象類沒有父子關(guān)系 ( 只能用接口接收代理對象 ) } }
使用 Cglib 代理
IA 接口 IA.java
public interface IA { public String show(String start); }
IA 實現(xiàn)類 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 用于創(chuàng)建代理對象的增強工具類 Enhancer enhancer = new Enhancer(); // Cglib需要對目標(biāo)對象的Class字節(jié)碼進行修改. // Cglib產(chǎn)生的代理對象實例.是目標(biāo)對象的子類 enhancer.setSuperclass(target.getClass()); // 只要是代理都會對原來的內(nèi)容進行增強操作 ( 增強就是在原有功能上 額外添加的功能 ) // setCallback() 設(shè)置用于增強 操作的實現(xiàn)類( MethodInterceptor對代理方法進行攔截 ) // 每次只要調(diào)用Cglib代理的方法,都會執(zhí)行 MethodInterceptor 接口中 intercept() 方法 enhancer.setCallback(new MethodInterceptor() { /** * intercept() 方法 跟 JDK 代理中的 InvocationHandler接口中 invoke() 功能完全一樣 * @param proxy Cglib代理對象實例 * @param method 調(diào)用方法的反射對象實例 * @param args 調(diào)用方法時傳遞的參數(shù) * @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); // 調(diào)用目標(biāo)方法 [加 / 減 / 乘 / 除 / 或具體方法] result = method.invoke(target, args); // 執(zhí)行增強代碼 LogUtils.logAfterReturning(method.getName(), args); }catch (Exception e){ e.printStackTrace(); LogUtils.logAfterThrowing(method.getName(), e); } return result; } }); // 創(chuàng)建 Cglib 代理對象實例 return enhancer.create(); } //測試 public static void main(String[] args) { // 目標(biāo)對象 Calculate calculate = new CalculateImpl(); // 創(chuàng)建代理對象實例 Calculate cglibProxy = (Calculate) createCglibProxy(calculate); // 調(diào)用代理方法式會執(zhí)行 MethodInterceptor 接口中 intercept() 方法 int result = cglibProxy.div(120, 0); // Cglib 代理 是目標(biāo)子類執(zhí)行 MethodInterceptor 接口中 intercept() 方法 System.out.println(cglibProxy instanceof Calculate); } }
優(yōu)點:在沒有接口的情況下,同樣可以實現(xiàn)代理的效果。
缺點:同樣需要自己編碼實現(xiàn)代理全部過程。
看完上述內(nèi)容,是不是對Java如何使用JDK與Cglib動態(tài)代理技術(shù)統(tǒng)一管理日志記錄有進一步的了解,如果還想學(xué)習(xí)更多內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。