最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java代理模式之靜態(tài)代理與動(dòng)態(tài)代理詳解

 更新時(shí)間:2026年01月13日 10:26:12   作者:祗久  
Java代理分為靜態(tài)代理和動(dòng)態(tài)代理,靜態(tài)代理需手動(dòng)編寫代理類,適合少量對(duì)象,動(dòng)態(tài)代理運(yùn)行時(shí)自動(dòng)生成代理類,適用于大量對(duì)象,如Spring AOP,這篇文章主要介紹了Java代理模式之靜態(tài)代理與動(dòng)態(tài)代理的相關(guān)資料,需要的朋友可以參考下

前言

在 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ā)InvocationHandlerinvoke方法,在該方法中統(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)景:

  1. Spring AOP:默認(rèn)優(yōu)先使用 JDK 動(dòng)態(tài)代理(目標(biāo)類有接口時(shí)),目標(biāo)類無接口時(shí)自動(dòng)切換為 CGLib;也可配置強(qiáng)制使用 CGLib。
  2. MyBatis:Mapper 接口的代理對(duì)象通過 JDK 動(dòng)態(tài)代理生成,綁定 SQL 執(zhí)行邏輯。
  3. 事務(wù)管理:Spring 的聲明式事務(wù)通過代理模式為方法添加事務(wù)增強(qiáng)。
  4. 日志 / 監(jiān)控:通過代理為方法統(tǒng)一添加日志打印、性能監(jiān)控邏輯,無需侵入業(yè)務(wù)代碼。

總結(jié)

  1. 靜態(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)代理。
  2. 三種代理方式的核心目的都是在不修改目標(biāo)類源碼的前提下增強(qiáng)方法邏輯,區(qū)別僅在于實(shí)現(xiàn)方式、性能和適用場(chǎng)景。
  3. 實(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)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot實(shí)現(xiàn)異步任務(wù)的項(xiàng)目實(shí)踐

    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ū)別

    Spring @Configuration和@Component的區(qū)別

    今天小編就為大家分享一篇關(guān)于Spring @Configuration和@Component的區(qū)別,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • 深入了解SpringBoot中的統(tǒng)一返回和統(tǒng)一異常處理

    深入了解SpringBoot中的統(tǒng)一返回和統(tǒng)一異常處理

    這篇文章主要為大家詳細(xì)介紹了SpringBoot項(xiàng)目中常用的統(tǒng)一返回結(jié)果和統(tǒng)一異常處理,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2024-01-01
  • Java中ArrayList和Vector的區(qū)別

    Java中ArrayList和Vector的區(qū)別

    本文主要介紹了Java中ArrayList和Vector的區(qū)別,包括線程安全性、性能、同步機(jī)制、擴(kuò)容機(jī)制、遍歷方式等,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-11-11
  • SpringBoot性能優(yōu)化的其中配置方法

    SpringBoot性能優(yōu)化的其中配置方法

    SpringBoot作為Java生態(tài)中最流行的微服務(wù)框架之一,以其開箱即用、快速開發(fā)的特性贏得了廣泛青睞,然而,許多開發(fā)者在日常使用中往往只關(guān)注了基礎(chǔ)功能,忽略了框架提供的許多高性能配置選項(xiàng),本文將深入剖析7個(gè)鮮為人知但極具價(jià)值的SpringBoot配置技巧
    2025-09-09
  • IDEA中Git的基本應(yīng)用詳解

    IDEA中Git的基本應(yīng)用詳解

    這篇文章主要介紹了IDEA中Git的基本應(yīng)用詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • 詳解Java中雪花算法的實(shí)現(xiàn)

    詳解Java中雪花算法的實(shí)現(xiàn)

    雪花算法是一種分布式的id生成算法。原理是將long分成若干個(gè)區(qū)段分別管理。本文將利用Java簡(jiǎn)單的實(shí)現(xiàn)雪花算法,感興趣的可以了解一下
    2022-12-12
  • 解決Maven多模塊編譯慢的問題

    解決Maven多模塊編譯慢的問題

    這篇文章主要介紹了Maven多模塊編譯慢的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 解決@Scheduled定時(shí)器使用@Thransactional事物問題

    解決@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文件方式

    這篇文章主要介紹了springboot項(xiàng)目實(shí)現(xiàn)定時(shí)備份數(shù)據(jù)庫導(dǎo)出sql文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03

最新評(píng)論

绥棱县| 炉霍县| 肃宁县| 南溪县| 临沧市| 舟山市| 神池县| 潢川县| 全椒县| 登封市| 鲁山县| 探索| 定兴县| 缙云县| 筠连县| 榆林市| 宜章县| 屏东县| 山丹县| 淳化县| 内丘县| 惠东县| 陕西省| 洞头县| 永川市| 平远县| 广丰县| 平乐县| 都匀市| 四平市| 三台县| 安丘市| 泽州县| 高碑店市| 义乌市| 双柏县| 南漳县| 桂阳县| 广平县| 屏山县| 桃园县|