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

