Java使用JDK與Cglib動(dòng)態(tài)代理技術(shù)統(tǒng)一管理日志記錄
Java中動(dòng)態(tài)代理主要有JDK和CGLIB兩種方式。
區(qū)別主要是jdk是代理接口,而cglib是代理類。
- 優(yōu)點(diǎn):這種方式已經(jīng)解決我們前面所有日記需要的問題。非常的靈活。而且可以方便的在后期進(jìn)行維護(hù)和升級(jí)。
- 缺點(diǎn):當(dāng)然使用jdk動(dòng)態(tài)代理,必需要有接口。如果沒有接口。就無法使用jdk動(dòng)態(tài)代理技術(shù)。
計(jì)算接口 Calculate.java
public interface Calculate { /** * 加法運(yùn)算 * @param num1 參數(shù) 1 * @param num2 參數(shù) 2 * @return */ public int add(int num1, int num2); /** * 加法運(yùn)算 * @param num1 參數(shù) 1 * @param num2 參數(shù) 2 * @param num3 參數(shù) 3 * @return */ public int add(int num1, int num2, int num3); /** * 除法運(yùn)算 * @param num1 參數(shù) 1 * @param num2 參數(shù) 2 * @return */ public int div(int num1, int num2); }
實(shí)現(xiàn)計(jì)算接口中的方法 CalculateImpl.java
/** * 實(shí)現(xiàn)計(jì)算接口中的方法 * 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)前操作,及運(yùn)算參數(shù) LogUtils.logBefore("add", num1, num2); int result = num1 + num2; return result; } @Override public int add(int num1, int num2, int num3) { // 記錄當(dāng)前操作,及運(yùn)算參數(shù) LogUtils.logBefore("add", num1, num2, num3); int result = num1 + num2 + num3; return result; } @Override public int div(int num1, int num2) { // 記錄當(dāng)前操作,及運(yùn)算參數(shù) LogUtils.logBefore("div", num1, num2); int result = 0; try { result = num1 / num2; // 記錄運(yùn)算結(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)前運(yùn)算操作 * @param args 當(dāng)前運(yùn)算參數(shù) */ public static void logBefore(String method, Object ... args){ System.out.println("操作運(yùn)算是 : " + 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)前操作運(yùn)算時(shí) : " + 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)前運(yùn)算時(shí) : " + method + " 發(fā)生的異常是 : " + e); } }
JDK 動(dòng)態(tài)代理的工廠類 JDKProxyFactory.java
/** * JDK 動(dòng)態(tài)代理的工廠 * Created by YongXin Xue on 2020/05/05 13:02 */ public class JDKProxyFactory { /** * 通過 JDK 底層自帶的 JDK 動(dòng)態(tài)代理技術(shù)解決日志需求問題 * @param target * @return */ public static Object createJDKProxy(Object target){ /** * Proxy 是Jdk中自帶的一個(gè)工具類(反射包下,屬于反射的功能). * Proxy類的作用: 它可以幫我們創(chuàng)建代理類或?qū)嵗? * 方法newProxyInstance()說明: 創(chuàng)建代理對(duì)象實(shí)例 * 第一個(gè)參數(shù)是: 目標(biāo)對(duì)象的類加載器 * 第二個(gè)參數(shù)是: 目標(biāo)對(duì)象實(shí)現(xiàn)的所有接口 * 第三個(gè)參數(shù)是: InvocationHandler 接口的實(shí)例 * InvocationHandler 接口的實(shí)現(xiàn)類可以對(duì)代理的目標(biāo)對(duì)象方法進(jìn)行增強(qiáng)操作. * 代理的目標(biāo)對(duì)象 ===>>> 需要額外增加功能的類(對(duì)象實(shí)例) * 增強(qiáng)操作 ===>>> 給原來功能添加的額外功能叫增強(qiáng)操作 ( 日記就是增強(qiáng)操作 ) */ return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { // 匿名內(nèi)部類 /** * invoke 方法是 InvocationHandler 接口中唯一的方法 * 代理對(duì)象每次調(diào)用方法時(shí),都會(huì)執(zhí)行 invoke() 方法 , 所有的增強(qiáng)操作都需要在invoke()方法中完成 * @param proxy 代理對(duì)象實(shí)例 * @param method 代理調(diào)用的方法的反射 Method 對(duì)象實(shí)例 * @param args 調(diào)用代理方法時(shí)傳遞進(jìn)來的參數(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í)行代理對(duì)象的(加法 / 除法 / 增強(qiáng)日志)操作 Object result = null; LogUtils.logBefore(method.getName(), args); try { // 1. 返回值是 method 方法調(diào)用時(shí)的返回值 result = method.invoke(target, args); // 2. 增強(qiáng)操作 LogUtils.logAfterReturning(method.getName(), result); }catch (Exception e){ LogUtils.logAfterThrowing(method.getName(), e); } // invoke() 返回代理方法的返回值 return result; } }); } // 測(cè)試代碼 public static void main(String[] args) { // 目標(biāo)對(duì)象 Calculate target = new CalculateImpl(); // 創(chuàng)建 Calculate 的代理對(duì)象實(shí)例 Calculate calculateProxy = (Calculate) createJDKProxy(target ); // jdk動(dòng)態(tài)代理對(duì)象實(shí)例和目標(biāo)對(duì)象實(shí)例 同宗同族 ( 他們都實(shí)現(xiàn)了相同的接口 ) System.out.println(calculateProxy instanceof Calculate); System.out.println(target instanceof Calculate); System.out.println( "代理方法的結(jié)果是 : " + calculateProxy.div(100,20) ); // jdk動(dòng)態(tài)代理創(chuàng)建出來的代理對(duì)象實(shí)例 是 目標(biāo)對(duì)象 接口的一個(gè)實(shí)現(xiàn)類 // 這個(gè)代理對(duì)象 和 目標(biāo)對(duì)象類沒有父子關(guān)系 ( 只能用接口接收代理對(duì)象 ) } }
使用 Cglib 代理
- Jdk動(dòng)態(tài)代理是通過實(shí)現(xiàn)目標(biāo)對(duì)象所有接口產(chǎn)生一個(gè)代理對(duì)象實(shí)例從而解決問題.
- 如果目標(biāo)對(duì)象沒有接口.則可以使用Cglib動(dòng)態(tài)代理技術(shù).
- Cglib動(dòng)態(tài)代理技術(shù)對(duì)目標(biāo)對(duì)象有沒有實(shí)現(xiàn)接口,沒有要求.
- Cglib動(dòng)態(tài)代理技術(shù),是通過拷貝然后修改目標(biāo)對(duì)象的類的字節(jié)碼來產(chǎn)生一個(gè)代理對(duì)象
- 而且這個(gè)Cglib產(chǎn)生的代理對(duì)象實(shí)例 是 目標(biāo)對(duì)象的一個(gè)子類.
IA 接口 IA.java
public interface IA { public String show(String start); }
IA 實(shí)現(xiàn)類 IAImpl.java
public class IAImpl implements IA { @Override public String show(String start) { System.out.println(start + "開始表演!"); return start + "表演的不錯(cuò)!!"; } }
使用 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)建代理對(duì)象的增強(qiáng)工具類 Enhancer enhancer = new Enhancer(); // Cglib需要對(duì)目標(biāo)對(duì)象的Class字節(jié)碼進(jìn)行修改. // Cglib產(chǎn)生的代理對(duì)象實(shí)例.是目標(biāo)對(duì)象的子類 enhancer.setSuperclass(target.getClass()); // 只要是代理都會(huì)對(duì)原來的內(nèi)容進(jìn)行增強(qiáng)操作 ( 增強(qiáng)就是在原有功能上 額外添加的功能 ) // setCallback() 設(shè)置用于增強(qiáng) 操作的實(shí)現(xiàn)類( MethodInterceptor對(duì)代理方法進(jìn)行攔截 ) // 每次只要調(diào)用Cglib代理的方法,都會(huì)執(zhí)行 MethodInterceptor 接口中 intercept() 方法 enhancer.setCallback(new MethodInterceptor() { /** * intercept() 方法 跟 JDK 代理中的 InvocationHandler接口中 invoke() 功能完全一樣 * @param proxy Cglib代理對(duì)象實(shí)例 * @param method 調(diào)用方法的反射對(duì)象實(shí)例 * @param args 調(diào)用方法時(shí)傳遞的參數(shù) * @param methodProxy 代理方法的method代理對(duì)象 * @return 是代理對(duì)象方法的返回值. * @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í)行增強(qiáng)代碼 LogUtils.logAfterReturning(method.getName(), args); }catch (Exception e){ e.printStackTrace(); LogUtils.logAfterThrowing(method.getName(), e); } return result; } }); // 創(chuàng)建 Cglib 代理對(duì)象實(shí)例 return enhancer.create(); } //測(cè)試 public static void main(String[] args) { // 目標(biāo)對(duì)象 Calculate calculate = new CalculateImpl(); // 創(chuàng)建代理對(duì)象實(shí)例 Calculate cglibProxy = (Calculate) createCglibProxy(calculate); // 調(diào)用代理方法式會(huì)執(zhí)行 MethodInterceptor 接口中 intercept() 方法 int result = cglibProxy.div(120, 0); // Cglib 代理 是目標(biāo)子類執(zhí)行 MethodInterceptor 接口中 intercept() 方法 System.out.println(cglibProxy instanceof Calculate); } }
優(yōu)點(diǎn):在沒有接口的情況下,同樣可以實(shí)現(xiàn)代理的效果。
缺點(diǎn):同樣需要自己編碼實(shí)現(xiàn)代理全部過程。
到此這篇關(guān)于Java使用JDK與Cglib動(dòng)態(tài)代理技術(shù)統(tǒng)一管理日志記錄的文章就介紹到這了,更多相關(guān)Java動(dòng)態(tài)代理統(tǒng)一管理日志 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java sleep方法及中斷方式、yield方法代碼實(shí)例
這篇文章主要介紹了Java sleep方法及中斷方式、yield方法代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04java8新特性-lambda表達(dá)式入門學(xué)習(xí)心得
這篇文章主要介紹了java8新特性-lambda表達(dá)式入門學(xué)習(xí)心得,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03springboot項(xiàng)目如何部署到服務(wù)器
這篇文章主要介紹了springboot項(xiàng)目如何部署到服務(wù)器問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05SpringBoot項(xiàng)目啟動(dòng)時(shí)預(yù)加載操作方法
Spring Boot是一種流行的Java開發(fā)框架,它提供了許多方便的功能來簡化應(yīng)用程序的開發(fā)和部署,這篇文章主要介紹了SpringBoot項(xiàng)目啟動(dòng)時(shí)預(yù)加載,需要的朋友可以參考下2023-09-09