Java代理模式之靜態(tài)代理與動(dòng)態(tài)代理詳解
前言
在 Java 開發(fā)中,代理模式是一種重要的結(jié)構(gòu)型設(shè)計(jì)模式,其核心思想是為目標(biāo)對(duì)象提供一個(gè)代理對(duì)象,由代理對(duì)象控制對(duì)目標(biāo)對(duì)象的訪問。代理模式可以在不修改目標(biāo)對(duì)象源碼的前提下,對(duì)目標(biāo)對(duì)象的方法進(jìn)行增強(qiáng)(如添加日志、權(quán)限校驗(yàn)、事務(wù)管理等)。
本文將詳細(xì)講解 Java 中三種常見的代理方式:靜態(tài)代理、JDK 動(dòng)態(tài)代理和 CGLib 動(dòng)態(tài)代理,并對(duì)比它們的特性與適用場(chǎng)景。
在正式講解代碼前,先明確代理模式的三個(gè)核心角色,后續(xù)所有實(shí)現(xiàn)都會(huì)圍繞這三個(gè)角色展開:
目標(biāo)接口:定義業(yè)務(wù)方法的規(guī)范,是代理類和目標(biāo)類的“約定”,明確了代理能代理哪些方法;
目標(biāo)類(被代理類):實(shí)現(xiàn)目標(biāo)接口,是真正執(zhí)行業(yè)務(wù)邏輯的類,比如下文代碼示例中用戶服務(wù)中“添加用戶”的核心邏輯就封裝在這里;
代理類:持有目標(biāo)類的引用,實(shí)現(xiàn)目標(biāo)接口(或繼承目標(biāo)類),在目標(biāo)方法的前后添加增強(qiáng)邏輯,最終對(duì)外提供服務(wù)。
代理模式的核心優(yōu)勢(shì)是“解耦”——將通用增強(qiáng)邏輯(如日志、權(quán)限)與核心業(yè)務(wù)邏輯分離,核心業(yè)務(wù)類只關(guān)注自身功能,通用邏輯統(tǒng)一由代理類管理,便于維護(hù)和擴(kuò)展。
靜態(tài)代理
靜態(tài)代理是最基礎(chǔ)的實(shí)現(xiàn)方式,特點(diǎn)是在編譯時(shí)手動(dòng)編寫代理類,代理類與目標(biāo)類一一對(duì)應(yīng),對(duì)同名業(yè)務(wù)方法進(jìn)行包裝。
核心原理
靜態(tài)代理要求代理類和目標(biāo)類實(shí)現(xiàn)同一個(gè)目標(biāo)接口,代理類內(nèi)部持有目標(biāo)類的引用,通過構(gòu)造器接收目標(biāo)對(duì)象;當(dāng)調(diào)用代理類的方法時(shí),會(huì)先執(zhí)行增強(qiáng)邏輯,再調(diào)用目標(biāo)對(duì)象的核心業(yè)務(wù)方法,最后執(zhí)行后置增強(qiáng)邏輯。
代碼示例
定義目標(biāo)接口,聲明業(yè)務(wù)方法:添加用戶的方法
public interface UserService {
//添加用戶
void addUser(String username);
}實(shí)現(xiàn)目標(biāo)類(業(yè)務(wù)實(shí)現(xiàn)類),實(shí)現(xiàn)目標(biāo)接口,執(zhí)行業(yè)務(wù)邏輯:模擬的添加用戶操作
public class UserServiceImpl implements UserService{
@Override
public void addUser(String username) {
System.out.println("添加用戶:" + username);
}
}定義靜態(tài)代理類,實(shí)現(xiàn)目標(biāo)接口,持有目標(biāo)對(duì)象,包裝業(yè)務(wù)方法
public class UserServiceStaticProxy implements UserService{
// 持有目標(biāo)對(duì)象,任何實(shí)現(xiàn)了這個(gè)接口的類,都能被這個(gè)代理類代理
private UserService target;
// 通過構(gòu)造器注入目標(biāo)對(duì)象,強(qiáng)制傳入目標(biāo)對(duì)象,避免空指針,讓代理知道要代理誰
public UserServiceStaticProxy(UserService target) {
this.target = target;
}
// 重寫addUser方法:這是代理的核心,包裝目標(biāo)方法
@Override
public void addUser(String username) {
// 前置增強(qiáng):調(diào)用目標(biāo)方法前的邏輯
System.out.println("靜態(tài)代理 - 前置:校驗(yàn)添加用戶權(quán)限");
// 調(diào)用目標(biāo)對(duì)象的業(yè)務(wù)方法,這是核心,代理類不做實(shí)際業(yè)務(wù),只是轉(zhuǎn)發(fā)
target.addUser(username);
// 后置增強(qiáng):調(diào)用目標(biāo)方法后的邏輯
System.out.println("靜態(tài)代理 - 后置:記錄添加用戶日志");
}
}測(cè)試,使用代理對(duì)象訪問目標(biāo)對(duì)象
public class StaticProxyTest {
public static void main(String[] args) {
// 創(chuàng)建目標(biāo)對(duì)象
UserService target = new UserServiceImpl();
// 創(chuàng)建代理對(duì)象并傳入目標(biāo)對(duì)象
UserService proxy = new UserServiceStaticProxy(target);
// 通過代理對(duì)象調(diào)用方法,用戶只和代理交互,不直接接觸目標(biāo)對(duì)象
proxy.addUser("張三");
}
}運(yùn)行結(jié)果

代碼細(xì)節(jié)解釋
(1)目標(biāo)接口UserService
定義了addUser方法,是代理類和目標(biāo)類的“約定”。為什么要定義接口?因?yàn)殪o態(tài)代理的核心是“面向接口編程”,后續(xù)代理類和目標(biāo)類都實(shí)現(xiàn)該接口,保證方法名、參數(shù)一致,同時(shí)提升靈活性(后續(xù)可替換目標(biāo)類實(shí)現(xiàn))。
(2)目標(biāo)類UserServiceImpl
實(shí)現(xiàn)UserService接口,重寫addUser方法,這里封裝的是“添加用戶”的核心業(yè)務(wù)邏輯——這是整個(gè)程序的核心功能,不包含任何通用增強(qiáng)邏輯,符合“單一職責(zé)原則”。
(3)代理類UserServiceStaticProxy
private UserService target;:聲明目標(biāo)對(duì)象引用,類型是接口UserService而非實(shí)現(xiàn)類UserServiceImpl。原因是“面向接口編程”,如果聲明為實(shí)現(xiàn)類,后續(xù)新增其他實(shí)現(xiàn)類(如帶緩存的UserServiceCacheImpl)時(shí),代理類無法復(fù)用,只能重新編寫,耦合度極高;而聲明為接口,任何實(shí)現(xiàn)該接口的類都能被代理,靈活性更強(qiáng)。構(gòu)造器
public UserServiceStaticProxy(UserService target):通過構(gòu)造器注入目標(biāo)對(duì)象,這是“依賴注入”的基礎(chǔ)。作用是強(qiáng)制創(chuàng)建代理對(duì)象時(shí)必須傳入目標(biāo)對(duì)象,避免target為空導(dǎo)致空指針異常,同時(shí)讓代理類與目標(biāo)類建立關(guān)聯(lián)。重寫
addUser方法:這是代理的核心邏輯。先執(zhí)行前置增強(qiáng)(權(quán)限校驗(yàn)),再通過target.addUser(username)調(diào)用目標(biāo)對(duì)象的核心業(yè)務(wù)方法,最后執(zhí)行后置增強(qiáng)(日志記錄)——用戶調(diào)用的是代理類的方法,全程不直接接觸目標(biāo)對(duì)象,實(shí)現(xiàn)了對(duì)目標(biāo)對(duì)象的控制。
(4)測(cè)試類StaticProxyTest
UserService target = new UserServiceImpl();:創(chuàng)建目標(biāo)對(duì)象,這是真正執(zhí)行業(yè)務(wù)的對(duì)象,相當(dāng)于“干活的人”。UserService proxy = new UserServiceStaticProxy(target);:創(chuàng)建代理對(duì)象,將目標(biāo)對(duì)象傳入,相當(dāng)于“找個(gè)中介,告訴中介要幫誰干活”。proxy.addUser("張三");:調(diào)用代理對(duì)象的方法,用戶只與中介(代理)交互,中介負(fù)責(zé)完成增強(qiáng)邏輯和核心業(yè)務(wù)邏輯的調(diào)用,實(shí)現(xiàn)了對(duì)目標(biāo)對(duì)象的“隔離”。
靜態(tài)代理的特點(diǎn)
- 優(yōu)點(diǎn):編譯時(shí)生成 class 字節(jié)碼文件,直接使用,執(zhí)行效率高;邏輯簡(jiǎn)單,易于理解和調(diào)試。
- 缺點(diǎn):代理類與目標(biāo)類一一對(duì)應(yīng),當(dāng)業(yè)務(wù)接口有多個(gè)方法或多個(gè)目標(biāo)類時(shí),需要編寫大量代理類,代碼冗余度高;一旦接口發(fā)生變更,目標(biāo)類和代理類都需要修改,維護(hù)成本高;靈活性差,無法動(dòng)態(tài)適配不同的目標(biāo)類。
動(dòng)態(tài)代理
JDK 動(dòng)態(tài)代理
為解決靜態(tài)代理的代碼冗余問題,Java提供了動(dòng)態(tài)代理機(jī)制——JDK動(dòng)態(tài)代理。其核心特點(diǎn)是運(yùn)行時(shí)動(dòng)態(tài)生成代理類字節(jié)碼,無需手動(dòng)編寫代理類,一個(gè)代理處理器可適配多個(gè)目標(biāo)類(只要實(shí)現(xiàn)接口)。
核心原理
JDK動(dòng)態(tài)代理依賴Java反射機(jī)制,核心是InvocationHandler接口(代理處理器)和Proxy類。目標(biāo)類必須實(shí)現(xiàn)至少一個(gè)接口,Proxy.newProxyInstance()方法會(huì)在運(yùn)行時(shí)生成一個(gè)實(shí)現(xiàn)目標(biāo)接口的代理類字節(jié)碼;當(dāng)調(diào)用代理對(duì)象的方法時(shí),會(huì)觸發(fā)InvocationHandler的invoke方法,在該方法中統(tǒng)一處理增強(qiáng)邏輯和目標(biāo)方法調(diào)用。
代碼示例
首先復(fù)用之前的UserService接口和UserServiceImpl實(shí)現(xiàn)類
定義JDK動(dòng)態(tài)代理處理器,實(shí)現(xiàn)InvocationHandler,統(tǒng)一處理增強(qiáng)邏輯
package com.qcby.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 定義JDK動(dòng)態(tài)代理處理器
*/
public class JdkDynamicProxyHandler implements InvocationHandler {
// 持有目標(biāo)對(duì)象(通用類型,適配不同接口)
private Object target;
public JdkDynamicProxyHandler(Object target) {
this.target = target;
}
/**
* 代理邏輯核心方法
*
* @param proxy 動(dòng)態(tài)生成的代理對(duì)象(一般不用)
* @param method 被代理的方法
* @param args 目標(biāo)方法入?yún)?
* @return 方法執(zhí)行結(jié)果
* @throws Throwable 異常
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增強(qiáng)
System.out.println("JDK動(dòng)態(tài)代理 - 前置:校驗(yàn)" + method.getName() + "方法權(quán)限");
// 通過反射調(diào)用目標(biāo)對(duì)象的方法
Object result = method.invoke(target, args);
// 后置增強(qiáng)
System.out.println("JDK動(dòng)態(tài)代理 - 后置:記錄" + method.getName() + "方法日志");
return result;
}
/**
* 生成動(dòng)態(tài)代理對(duì)象的入口方法
* @return 動(dòng)態(tài)生成的代理對(duì)象(實(shí)現(xiàn)目標(biāo)接口)
*/
public Object getProxyInstance() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 目標(biāo)類的類加載器,用于加載動(dòng)態(tài)生成的代理類字節(jié)碼
target.getClass().getInterfaces(), // 目標(biāo)類實(shí)現(xiàn)的接口,JDK代理的核心,代理類會(huì)實(shí)現(xiàn)這些接口
this // 當(dāng)前InvocationHandler實(shí)例:告訴代理類增強(qiáng)邏輯在哪里
);
}
}
測(cè)試
public class JdkDynamicProxyTest {
public static void main(String[] args) {
// 創(chuàng)建目標(biāo)對(duì)象
UserService target = new UserServiceImpl();
// 創(chuàng)建代理處理器,傳入目標(biāo)對(duì)象
JdkDynamicProxyHandler handler = new JdkDynamicProxyHandler(target);
// 生成動(dòng)態(tài)代理對(duì)象:JDK在運(yùn)行時(shí)自動(dòng)創(chuàng)建代理類字節(jié)碼并實(shí)例化
UserService proxy = (UserService) handler.getProxyInstance();
// 調(diào)用代理方法,觸發(fā)invoke方法
proxy.addUser("李四");
}
}運(yùn)行結(jié)果

代碼細(xì)節(jié)解釋
(1)核心接口InvocationHandler
這是JDK動(dòng)態(tài)代理的“增強(qiáng)邏輯處理器”,所有的增強(qiáng)邏輯都寫在其invoke方法中。任何JDK動(dòng)態(tài)代理都必須實(shí)現(xiàn)這個(gè)接口,它是代理類和增強(qiáng)邏輯的橋梁。
(2)代理處理器JdkDynamicProxyHandler
private Object target;:用Object類型持有目標(biāo)對(duì)象,原因是該處理器要適配所有實(shí)現(xiàn)接口的目標(biāo)類(如UserService、OrderService等),若寫死為UserService,就只能代理這一個(gè)接口,失去了動(dòng)態(tài)代理的靈活性。構(gòu)造器
public JdkDynamicProxyHandler(Object target):和靜態(tài)代理一樣,通過構(gòu)造器注入目標(biāo)對(duì)象,建立處理器與目標(biāo)對(duì)象的關(guān)聯(lián),避免空指針。核心方法
invoke(Object proxy, Method method, Object[] args):這是JDK動(dòng)態(tài)代理的核心,所有代理對(duì)象的方法調(diào)用都會(huì)觸發(fā)此方法:proxy:動(dòng)態(tài)生成的代理對(duì)象(如$Proxy0),一般不用,因?yàn)槲覀冴P(guān)注的是目標(biāo)方法的調(diào)用,而非代理對(duì)象本身;method:被代理的目標(biāo)方法對(duì)象,通過它可以獲取方法名(method.getName())、參數(shù)類型等信息,實(shí)現(xiàn)通用增強(qiáng)邏輯(如對(duì)所有方法統(tǒng)一加日志);args:目標(biāo)方法的入?yún)?,需要傳遞給目標(biāo)方法;method.invoke(target, args):通過反射調(diào)用目標(biāo)對(duì)象的方法,這是JDK動(dòng)態(tài)代理的核心機(jī)制。反射的作用是“動(dòng)態(tài)找到并調(diào)用目標(biāo)方法”,無需提前知道具體方法名,因此能適配多個(gè)目標(biāo)類;前置/后置增強(qiáng):和靜態(tài)代理邏輯一致,只是這里的增強(qiáng)邏輯是通用的,可復(fù)用在所有代理的目標(biāo)方法上。
getProxyInstance():生成代理對(duì)象的入口,核心是Proxy.newProxyInstance()方法,該方法接收三個(gè)參數(shù):參數(shù)1(類加載器):目標(biāo)類的類加載器,用于加載運(yùn)行時(shí)動(dòng)態(tài)生成的代理類字節(jié)碼(代理類是臨時(shí)的,只存在于內(nèi)存中);
參數(shù)2(接口數(shù)組):目標(biāo)類實(shí)現(xiàn)的所有接口,JDK動(dòng)態(tài)代理的核心限制——代理類會(huì)實(shí)現(xiàn)這些接口,因此代理對(duì)象才能強(qiáng)轉(zhuǎn)為目標(biāo)接口類型(如UserService);
參數(shù)3(InvocationHandler):當(dāng)前處理器實(shí)例,告訴代理類“增強(qiáng)邏輯在哪里”,代理對(duì)象調(diào)用方法時(shí)會(huì)觸發(fā)該處理器的invoke方法。
(3)測(cè)試類JdkDynamicProxyTest
UserService target = new UserServiceImpl();:創(chuàng)建目標(biāo)對(duì)象,和靜態(tài)代理一致;JdkDynamicProxyHandler handler = new JdkDynamicProxyHandler(target);:創(chuàng)建處理器,傳入目標(biāo)對(duì)象,相當(dāng)于“找個(gè)萬能中介,告訴中介要幫誰干活”;UserService proxy = (UserService) handler.getProxyInstance();:生成代理對(duì)象,這里的proxy是JDK在運(yùn)行時(shí)動(dòng)態(tài)生成的代理類實(shí)例(類名類似$Proxy0),因?yàn)榇眍悓?shí)現(xiàn)了UserService接口,所以能強(qiáng)轉(zhuǎn)為UserService類型;proxy.addUser("李四");:調(diào)用代理對(duì)象方法,觸發(fā)handler的invoke方法,執(zhí)行增強(qiáng)邏輯和目標(biāo)方法調(diào)用。
JDK 動(dòng)態(tài)代理的特點(diǎn)
- 優(yōu)點(diǎn):無需手動(dòng)編寫代理類,一個(gè)處理器可代理多個(gè)接口的類,減少代碼冗余;運(yùn)行時(shí)動(dòng)態(tài)生成代理,靈活性極高,符合“開閉原則”(新增目標(biāo)類無需修改處理器);
- 缺點(diǎn):依賴反射機(jī)制調(diào)用方法,反射調(diào)用方法的性能略低于靜態(tài)代理和 CGLib;只能代理實(shí)現(xiàn)了接口的類,無法代理普通類(無接口)。
CGLib 動(dòng)態(tài)代理
JDK動(dòng)態(tài)代理無法代理無接口的普通類,因此第三方庫CGLib(Code Generation Library)彌補(bǔ)了這一不足。CGLib的核心特點(diǎn)是通過繼承目標(biāo)類生成子類作為代理類,無需目標(biāo)類實(shí)現(xiàn)接口,運(yùn)行時(shí)動(dòng)態(tài)生成子類字節(jié)碼,通過重寫目標(biāo)方法實(shí)現(xiàn)代理。
核心原理
CGLib依賴ASM字節(jié)碼框架,直接操作字節(jié)碼生成目標(biāo)類的子類(代理類);代理類重寫目標(biāo)類的所有非final方法,當(dāng)調(diào)用代理對(duì)象的方法時(shí),會(huì)觸發(fā)MethodInterceptor(方法攔截器)的intercept方法,在該方法中處理增強(qiáng)邏輯和目標(biāo)方法調(diào)用。由于是繼承實(shí)現(xiàn),目標(biāo)類和目標(biāo)方法不能是final(final類無法繼承,final方法無法重寫)。
代碼示例
CGLib是第三方庫,需手動(dòng)引入依賴(Spring等框架已內(nèi)置CGLib,可直接使用)。Maven依賴如下:
<!-- Maven依賴(如需手動(dòng)引入) -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>定義普通業(yè)務(wù)類(無需實(shí)現(xiàn)接口)
public class OrderService {
// 非final方法:CGLib需要重寫該方法
public void createOrder(String orderNo) {
System.out.println("創(chuàng)建訂單:" + orderNo);
}
}定義CGLib方法攔截器:實(shí)現(xiàn)MethodInterceptor,處理增強(qiáng)邏輯
package com.qcby.cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// 定義CGLib代理攔截器
public class CglibDynamicProxyInterceptor implements MethodInterceptor {
// 持有目標(biāo)對(duì)象
private Object target;
public CglibDynamicProxyInterceptor(Object target) {
this.target = target;
}
/**
* 創(chuàng)建CGLib代理對(duì)象(目標(biāo)類的子類)
* @return 代理對(duì)象(子類實(shí)例)
*/
public Object getProxyInstance() {
// Enhancer:CGLib的核心類,用于生成目標(biāo)類的子類(代理類)
Enhancer enhancer = new Enhancer();
// 設(shè)置父類(目標(biāo)類),代理類是該類的子類
enhancer.setSuperclass(target.getClass());
// 設(shè)置回調(diào)方法(攔截器),代理類的方法調(diào)用都會(huì)觸發(fā)當(dāng)前攔截器的intercept方法
enhancer.setCallback(this);
// 生成并返回代理對(duì)象(子類實(shí)例)
return enhancer.create();
}
/**
* 攔截方法(代理邏輯核心),所有代理對(duì)象的方法調(diào)用都會(huì)觸發(fā)此方法
* @param proxy 代理對(duì)象(目標(biāo)類的子類實(shí)例)
* @param method 被攔截的目標(biāo)方法(父類方法)
* @param args 方法入?yún)?
* @param methodProxy 方法代理對(duì)象:CGLib生成的,用于調(diào)用父類方法
* @return 方法執(zhí)行結(jié)果
* @throws Throwable 異常
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 前置增強(qiáng)
System.out.println("CGLib動(dòng)態(tài)代理 - 前置:校驗(yàn)" + method.getName() + "方法權(quán)限");
// 調(diào)用目標(biāo)類(父類)的方法(非反射,性能更高)
Object result = methodProxy.invokeSuper(proxy, args);
// 后置增強(qiáng)
System.out.println("CGLib動(dòng)態(tài)代理 - 后置:記錄" + method.getName() + "方法日志");
return result;
}
}
測(cè)試
public class CglibDynamicProxyTest {
public static void main(String[] args) {
// 創(chuàng)建目標(biāo)對(duì)象
OrderService target = new OrderService();
// 創(chuàng)建CGLib攔截器,傳入目標(biāo)對(duì)象
CglibDynamicProxyInterceptor interceptor = new CglibDynamicProxyInterceptor(target);
// 生成代理對(duì)象(目標(biāo)類的子類)
OrderService proxy = (OrderService) interceptor.getProxyInstance();
// 調(diào)用代理對(duì)象方法:觸發(fā)intercept方法
proxy.createOrder("ORDER_20251226");
}
}運(yùn)行結(jié)果

代碼細(xì)節(jié)解釋
(1)目標(biāo)類OrderService
普通類,無任何接口,核心業(yè)務(wù)邏輯是createOrder方法。注意:該類和方法不能是final——CGLib是通過繼承實(shí)現(xiàn)代理的,final類無法被繼承,final方法無法被重寫,會(huì)導(dǎo)致代理失敗。這是CGLib的核心限制。
(2)方法攔截器CglibDynamicProxyInterceptor
private Object target;:用Object類型持有目標(biāo)對(duì)象,適配所有普通類(無接口),提升攔截器的復(fù)用性。構(gòu)造器
public CglibDynamicProxyInterceptor(Object target):注入目標(biāo)對(duì)象,建立攔截器與目標(biāo)對(duì)象的關(guān)聯(lián),和前兩種代理邏輯一致。getProxyInstance():生成代理對(duì)象的入口,核心是Enhancer類(CGLib的“子類生成器”):enhancer.setSuperclass(target.getClass()):設(shè)置代理類的父類為目標(biāo)類,這是CGLib的核心——代理類是目標(biāo)類的子類,因此代理對(duì)象才能強(qiáng)轉(zhuǎn)為目標(biāo)類類型(如OrderService);enhancer.setCallback(this):設(shè)置回調(diào)攔截器,告訴代理類“增強(qiáng)邏輯在哪里”,代理對(duì)象調(diào)用方法時(shí)會(huì)觸發(fā)當(dāng)前攔截器的intercept方法;enhancer.create():生成并返回代理對(duì)象(目標(biāo)類的子類實(shí)例),CGLib會(huì)在運(yùn)行時(shí)動(dòng)態(tài)生成子類字節(jié)碼并實(shí)例化。
核心方法
intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy):所有代理對(duì)象的方法調(diào)用都會(huì)觸發(fā)此方法:proxy:動(dòng)態(tài)生成的代理對(duì)象(目標(biāo)類的子類實(shí)例,如OrderService$$EnhancerByCGLIB$$xxxx);method:被攔截的目標(biāo)方法(父類OrderService的createOrder方法);args:目標(biāo)方法的入?yún)ⅲ?/p>methodProxy:CGLib生成的方法代理對(duì)象,用于調(diào)用父類(目標(biāo)類)的方法;methodProxy.invokeSuper(proxy, args):核心!調(diào)用父類(目標(biāo)類)的方法,這不是反射。CGLib在生成子類時(shí),會(huì)直接生成調(diào)用父類方法的字節(jié)碼,因此執(zhí)行效率比JDK動(dòng)態(tài)代理的反射更高;前置/后置增強(qiáng):通用邏輯,可復(fù)用在所有代理的目標(biāo)方法上。
(3)測(cè)試類CglibDynamicProxyTest
OrderService target = new OrderService();:創(chuàng)建目標(biāo)對(duì)象(普通類,無接口);CglibDynamicProxyInterceptor interceptor = new CglibDynamicProxyInterceptor(target);:創(chuàng)建攔截器,傳入目標(biāo)對(duì)象;OrderService proxy = (OrderService) interceptor.getProxyInstance();:生成代理對(duì)象(目標(biāo)類的子類實(shí)例),因此能強(qiáng)轉(zhuǎn)為OrderService類型;proxy.createOrder("ORDER_20251226");:調(diào)用代理對(duì)象方法,觸發(fā)intercept方法,執(zhí)行增強(qiáng)邏輯和目標(biāo)方法調(diào)用。
CGLib 動(dòng)態(tài)代理的特點(diǎn)
- 優(yōu)點(diǎn):無需目標(biāo)類實(shí)現(xiàn)接口,適用范圍更廣;直接生成字節(jié)碼,調(diào)用方法無需反射,性能優(yōu)于 JDK 動(dòng)態(tài)代理;一個(gè)攔截器可適配多個(gè)普通類,靈活性高;
- 缺點(diǎn):依賴第三方庫(需引入CGLib);代理類繼承目標(biāo)類,受限于繼承的特性(目標(biāo)類 / 方法不能是 final);生成子類字節(jié)碼,內(nèi)存占用略高于 JDK 動(dòng)態(tài)代理。
總結(jié)
三種代理方式的全面對(duì)比:

實(shí)際應(yīng)用場(chǎng)景:
- Spring AOP:默認(rèn)優(yōu)先使用 JDK 動(dòng)態(tài)代理(目標(biāo)類有接口時(shí)),目標(biāo)類無接口時(shí)自動(dòng)切換為 CGLib;也可配置強(qiáng)制使用 CGLib。
- MyBatis:Mapper 接口的代理對(duì)象通過 JDK 動(dòng)態(tài)代理生成,綁定 SQL 執(zhí)行邏輯。
- 事務(wù)管理:Spring 的聲明式事務(wù)通過代理模式為方法添加事務(wù)增強(qiáng)。
- 日志 / 監(jiān)控:通過代理為方法統(tǒng)一添加日志打印、性能監(jiān)控邏輯,無需侵入業(yè)務(wù)代碼。
總結(jié)
- 靜態(tài)代理適合簡(jiǎn)單、固定的業(yè)務(wù)場(chǎng)景,執(zhí)行效率高但靈活性差;JDK 動(dòng)態(tài)代理依賴接口和反射,適配多數(shù)有接口的代理場(chǎng)景;CGLib 通過繼承實(shí)現(xiàn),適合無接口的普通類代理,性能優(yōu)于 JDK 動(dòng)態(tài)代理。
- 三種代理方式的核心目的都是在不修改目標(biāo)類源碼的前提下增強(qiáng)方法邏輯,區(qū)別僅在于實(shí)現(xiàn)方式、性能和適用場(chǎng)景。
- 實(shí)際開發(fā)中(如 Spring),框架已封裝了代理的底層實(shí)現(xiàn),只需關(guān)注增強(qiáng)邏輯,無需手動(dòng)實(shí)現(xiàn)代理細(xì)節(jié),但理解三種代理的原理有助于排查問題和優(yōu)化性能。
到此這篇關(guān)于Java代理模式之靜態(tài)代理與動(dòng)態(tài)代理詳解的文章就介紹到這了,更多相關(guān)Java靜態(tài)代理與動(dòng)態(tài)代理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 一文搞懂Java常見的三種代理模式(靜態(tài)代理、動(dòng)態(tài)代理和cglib代理)
- 淺談Java代理(jdk靜態(tài)代理、動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理)
- Java靜態(tài)代理和動(dòng)態(tài)代理總結(jié)
- java 靜態(tài)代理 動(dòng)態(tài)代理深入學(xué)習(xí)
- 深入解析java中的靜態(tài)代理與動(dòng)態(tài)代理
- Java代理模式之靜態(tài)代理與動(dòng)態(tài)代理的區(qū)別及優(yōu)缺點(diǎn)
- 淺析Java中靜態(tài)代理和動(dòng)態(tài)代理的應(yīng)用與區(qū)別
- 深入理解Java動(dòng)態(tài)代理與靜態(tài)代理
相關(guān)文章
SpringBoot實(shí)現(xiàn)異步任務(wù)的項(xiàng)目實(shí)踐
本文將使用SpringBoot 去實(shí)現(xiàn)異步之間的調(diào)用,提高系統(tǒng)的并發(fā)性能、用戶體驗(yàn),具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10
Spring @Configuration和@Component的區(qū)別
今天小編就為大家分享一篇關(guān)于Spring @Configuration和@Component的區(qū)別,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12
深入了解SpringBoot中的統(tǒng)一返回和統(tǒng)一異常處理
這篇文章主要為大家詳細(xì)介紹了SpringBoot項(xiàng)目中常用的統(tǒng)一返回結(jié)果和統(tǒng)一異常處理,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2024-01-01
解決@Scheduled定時(shí)器使用@Thransactional事物問題
這篇文章主要介紹了解決@Scheduled定時(shí)器使用@Thransactional事物問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
springboot項(xiàng)目實(shí)現(xiàn)定時(shí)備份數(shù)據(jù)庫導(dǎo)出sql文件方式
這篇文章主要介紹了springboot項(xiàng)目實(shí)現(xiàn)定時(shí)備份數(shù)據(jù)庫導(dǎo)出sql文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03

