成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

詳解JDK動(dòng)態(tài)代理和CGLib動(dòng)態(tài)代理

開發(fā) 后端
代理模式(Proxy Pattern)是23種設(shè)計(jì)模式中的一種,屬于結(jié)構(gòu)型設(shè)計(jì)模式。代理模式給某一個(gè)對(duì)象提供一個(gè)代理,并由代理對(duì)象控制原對(duì)象的引用。代理對(duì)象在客戶端和目標(biāo)對(duì)象之間起到中介作用。

代理模式

代理模式(Proxy Pattern)是23種設(shè)計(jì)模式中的一種,屬于結(jié)構(gòu)型設(shè)計(jì)模式。代理模式給某一個(gè)對(duì)象提供一個(gè)代理,并由代理對(duì)象控制原對(duì)象的引用。代理對(duì)象在客戶端和目標(biāo)對(duì)象之間起到中介作用。

舉個(gè)例子:你要去吃飯,你可以選擇自己在家做飯、吃飯、刷碗,所有的事情都自己做;也可以選擇去餐廳,自己只是吃飯,把做飯和刷碗的活兒都交給代理對(duì)象,也就是餐廳的工作人員。

下圖是代理模式的通用類圖。結(jié)合例子,就很容易理解了。

代理模式通用類圖

代理模式包含如下角色:

  • Subject (抽象主題角色) 抽象主題角色聲明了真實(shí)主題和代理主題的共同接口,這樣一來在任何使用真實(shí)主題 的地方都可以使用代理主題。客戶端需要針對(duì)抽象主題角色進(jìn)行編程。
  • Proxy (代理主題角色) 代理主題角色內(nèi)部包含對(duì)真實(shí)主題的引用,從而可以在任何時(shí)候操作真實(shí)主題對(duì)象。 在代理主題角色中提供一個(gè)與真實(shí)主題角色相同的接口,以便在任何時(shí)候都可以替代真實(shí)主體。代理主題角色還可以控制對(duì)真實(shí)主題的使用,負(fù)責(zé)在需要的時(shí)候創(chuàng)建和刪除真實(shí)主題對(duì)象,并對(duì)真實(shí)主題對(duì)象的使用加以約束。代理角色通常在客戶端調(diào)用所引用的真實(shí)主題操作之前或之后還需要執(zhí)行其他操作,而不僅僅是單純的調(diào)用真實(shí)主題對(duì)象中的操作。
  • RealSubject (真實(shí)主題角色) 真實(shí)主題角色定義了代理角色所代表的真實(shí)對(duì)象,在真實(shí)主題角色中實(shí)現(xiàn)了真實(shí)的業(yè)務(wù)操作,客戶端可以通過代理主題角色間接調(diào)用真實(shí)主題角色中定義的方法。

代理模式可以分為靜態(tài)代理和動(dòng)態(tài)代理兩種類型,而動(dòng)態(tài)代理中又分為JDK動(dòng)態(tài)代理和CGLIB代理兩種。

JDK動(dòng)態(tài)代理

在jdk的動(dòng)態(tài)代理機(jī)制中,有幾個(gè)重要的角色:

  • Interface:對(duì)于JDK Proxy,業(yè)務(wù)類是需要一個(gè)Interface的。
  • Proxy:Proxy類是動(dòng)態(tài)產(chǎn)生的,這個(gè)類在調(diào)用Proxy.newProxyInstance()方法之后,產(chǎn)生一個(gè)Proxy類的實(shí)例。實(shí)際上,這個(gè)Proxy類也是存在的,不僅僅是類的實(shí)例,這個(gè)Proxy類可以保存在硬盤上。
  • Method:對(duì)于業(yè)務(wù)委托類的每個(gè)方法,現(xiàn)在Proxy類里面都不用靜態(tài)顯示出來。
  • InvocationHandler:這個(gè)類在業(yè)務(wù)委托類執(zhí)行時(shí),會(huì)先調(diào)用invoke方法。invoke方法再執(zhí)行想要的代理操作,可以實(shí)現(xiàn)對(duì)業(yè)務(wù)方法的再包裝。

(1)InvocationHandler

每一個(gè)動(dòng)態(tài)代理類都必須要實(shí)現(xiàn)InvocationHandler這個(gè)接口,并且每個(gè)代理類的實(shí)例都關(guān)聯(lián)了一個(gè)handler,當(dāng)我們通過代理對(duì)象調(diào)用一個(gè)方法的時(shí)候,這個(gè)方法的調(diào)用就會(huì)被轉(zhuǎn)發(fā)為由InvocationHandler這個(gè)接口的 invoke 方法來進(jìn)行調(diào)用。

InvocationHandler這個(gè)接口的唯一一個(gè)方法 invoke 方法:

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

這個(gè)方法一共接受三個(gè)參數(shù),那么這三個(gè)參數(shù)分別代表如下:

  • proxy:指代JDK動(dòng)態(tài)生成的最終代理對(duì)象
  • method:指代的是我們所要調(diào)用真實(shí)對(duì)象的某個(gè)方法的Method對(duì)象
  • args:指代的是調(diào)用真實(shí)對(duì)象某個(gè)方法時(shí)接受的參數(shù)

(2)Proxy

Proxy這個(gè)類的作用就是用來動(dòng)態(tài)創(chuàng)建一個(gè)代理對(duì)象的類,它提供了許多的方法,但是我們用的最多的就是newProxyInstance 這個(gè)方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) throws IllegalArgumentException

這個(gè)方法的作用就是得到一個(gè)動(dòng)態(tài)的代理對(duì)象,其接收三個(gè)參數(shù),我們來看看這三個(gè)參數(shù)所代表的含義:

  • loader:ClassLoader對(duì)象,定義了由哪個(gè)ClassLoader來對(duì)生成的代理對(duì)象進(jìn)行加載,即代理類的類加載器。
  • interfaces:Interface對(duì)象的數(shù)組,表示的是我將要給我需要代理的對(duì)象提供一組什么接口,如果我提供了一組接口給它,那么這個(gè)代理對(duì)象就宣稱實(shí)現(xiàn)了該接口(多態(tài)),這樣我就能調(diào)用這組接口中的方法了。
  • Handler:InvocationHandler對(duì)象,表示的是當(dāng)我這個(gè)動(dòng)態(tài)代理對(duì)象在調(diào)用方法的時(shí)候,會(huì)關(guān)聯(lián)到哪一個(gè)InvocationHandler對(duì)象上。

所以我們所說的DynamicProxy(動(dòng)態(tài)代理類)是這樣一種class:它是在運(yùn)行時(shí)生成的class,在生成它時(shí)你必須提供一組interface給它,然后該class就宣稱它實(shí)現(xiàn)了這些 interface。這個(gè)DynamicProxy其實(shí)就是一個(gè)Proxy,它不會(huì)做實(shí)質(zhì)性的工作,在生成它的實(shí)例時(shí)你必須提供一個(gè)handler,由它接管實(shí)際的工作。

(3)代碼實(shí)現(xiàn)

被代理對(duì)象:

/**
 * 抽象主題角色
 */
interface Subject {
    void eat();
}

/**
 * 真實(shí)主題角色 - 你自己 - 專注吃飯
 */
class YourSelf implements Subject{

    @Override
    public void eat() {
        System.out.println("自己吃飯");
    }
}

代理對(duì)象:

/**
 * 代理主題角色 - 餐廳
 * 每次生成動(dòng)態(tài)代理類對(duì)象時(shí)都需要指定一個(gè)實(shí)現(xiàn)了InvocationHandler接口的調(diào)用處理器對(duì)象
 */
class JdkProxySubject implements InvocationHandler {

    // 這個(gè)就是我們要代理的真實(shí)對(duì)象,也就是真正執(zhí)行業(yè)務(wù)邏輯的類
    private Object target;

    // 通過構(gòu)造方法傳入這個(gè)被代理對(duì)象
    public JdkProxySubject(Object target) {
        super();
        this.target = target;
    }

    // 創(chuàng)建代理對(duì)象
    public Object createProxy() {
        // 1.得到目標(biāo)對(duì)象的類加載器
        ClassLoader classLoader = target.getClass().getClassLoader();
        // 2.得到目標(biāo)對(duì)象的實(shí)現(xiàn)接口
        Class<?>[] interfaces = target.getClass().getInterfaces();
        // 3.第三個(gè)參數(shù)需要一個(gè)實(shí)現(xiàn)invocationHandler接口的對(duì)象
        Object newProxyInstance = Proxy.newProxyInstance(classLoader, interfaces, this);
        return newProxyInstance;
    }


    // 當(dāng)代理對(duì)象調(diào)用真實(shí)對(duì)象的方法時(shí),其會(huì)自動(dòng)的跳轉(zhuǎn)到代理對(duì)象關(guān)聯(lián)的handler對(duì)象的invoke方法來進(jìn)行調(diào)用
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("餐廳工作人員做飯......");
        Object invoke = method.invoke(target, args);
        System.out.println("餐廳工作人員刷碗......");
        return invoke;
    }
}

測試類:

/**
 * 測試類
 * @author tianxiaopeng@hxy
 * @date 2023/10/11 11:09 AM
 */
public class ProxyTest {
    public static void main(String[] args) {
        // 1.創(chuàng)建對(duì)象
        YourSelf yourSelf = new YourSelf();
        // 2.創(chuàng)建代理對(duì)象
        JdkProxySubject proxy = new JdkProxySubject(yourSelf);
        // 3.調(diào)用代理對(duì)象的增強(qiáng)方法,得到增強(qiáng)后的對(duì)象
        Subject createProxy = (Subject) proxy.createProxy();
        createProxy.eat();
    }
}

CGLIB動(dòng)態(tài)代理

JDK動(dòng)態(tài)代理是通過重寫被代理對(duì)象實(shí)現(xiàn)的接口中的方法來實(shí)現(xiàn),而CGLIB是通過繼承被代理對(duì)象來實(shí)現(xiàn),和JDK動(dòng)態(tài)代理需要實(shí)現(xiàn)指定接口一樣,CGLIB也要求代理對(duì)象必須要實(shí)現(xiàn)MethodInterceptor接口,并重寫其唯一的方法intercept。

CGLib采用了非常底層的字節(jié)碼技術(shù),其原理是通過字節(jié)碼技術(shù)為一個(gè)類創(chuàng)建子類,并在子類中采用方法攔截的技術(shù)攔截所有父類方法的調(diào)用,順勢(shì)織入橫切邏輯。(利用ASM開源包,對(duì)代理對(duì)象類的class文件加載進(jìn)來,通過修改其字節(jié)碼生成子類來處理)

注意:因?yàn)镃GLIB是通過繼承目標(biāo)類來重寫其方法來實(shí)現(xiàn)的,故而如果是final和private方法則無法被重寫,也就是無法被代理。

<dependency>
    <groupId>cglib</groupId>
	<artifactId>cglib-nodep</artifactId>
	<version>2.2</version>
</dependency>

(1)CGLib核心類

net.sf.cglib.proxy.Enhancer:主要增強(qiáng)類,通過字節(jié)碼技術(shù)動(dòng)態(tài)創(chuàng)建委托類的子類實(shí)例。

Enhancer可能是CGLIB中最常用的一個(gè)類,和Java1.3動(dòng)態(tài)代理中引入的Proxy類差不多。和Proxy不同的是,Enhancer既能夠代理普通的class,也能夠代理接口。Enhancer創(chuàng)建一個(gè)被代理對(duì)象的子類并且攔截所有的方法調(diào)用(包括從Object中繼承的toString和hashCode方法)。Enhancer不能夠攔截final方法,例如Object.getClass()方法,這是由于Java final方法語義決定的。基于同樣的道理,Enhancer也不能對(duì)fianl類進(jìn)行代理操作。這也是Hibernate為什么不能持久化final class的原因。

net.sf.cglib.proxy.MethodInterceptor:常用的方法攔截器接口,需要實(shí)現(xiàn)intercept方法,實(shí)現(xiàn)具體攔截處理。

public java.lang.Object intercept(java.lang.Object obj,
                                   java.lang.reflect.Method method,
                                   java.lang.Object[] args,
                                   MethodProxy proxy) throws java.lang.Throwable{}
  • obj:動(dòng)態(tài)生成的代理對(duì)象。
  • method:實(shí)際調(diào)用的方法。
  • args:調(diào)用方法入?yún)ⅰ?/li>
  • net.sf.cglib.proxy.MethodProxy:java Method類的代理類,可以實(shí)現(xiàn)委托類對(duì)象的方法的調(diào)用;常用方法:methodProxy.invokeSuper(proxy, args);在攔截方法內(nèi)可以調(diào)用多次。

(2)CGLib代理實(shí)例

創(chuàng)建被代理類。

/**
 * 真實(shí)主題角色 - 你自己 - 專注吃飯
 */
class YourSelf {
    public void eat(){
        System.out.println("自己吃飯");
    }
}

創(chuàng)建代理類:

/**
 * 代理主題角色 - 餐廳
 */
class ProxyCglib implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();
    public Object getProxy(Class clazz){
        //設(shè)置需要?jiǎng)?chuàng)建子類的類
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        //通過字節(jié)碼技術(shù)動(dòng)態(tài)創(chuàng)建子類實(shí)例
        return enhancer.create();
    }

    //實(shí)現(xiàn)MethodInterceptor接口方法
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("餐廳工作人員做飯......");
        //通過代理類調(diào)用父類中的方法
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("餐廳工作人員刷碗......");
        return result;
    }
}

測試類:

/**
 * 測試類
 * @author tianxiaopeng@hxy
 * @date 2023/10/11 11:51 AM
 */
public class CglibTest {
    public static void main(String[] args) {
        ProxyCglib proxy = new ProxyCglib();
        //通過生成子類的方式創(chuàng)建代理類
        YourSelf proxyImp = (YourSelf)proxy.getProxy(YourSelf.class);
        proxyImp.eat();
    }
}

結(jié)果:

餐廳工作人員做飯......
自己吃飯
餐廳工作人員刷碗......

(2)CGLIB動(dòng)態(tài)代理實(shí)現(xiàn)分析

CGLib動(dòng)態(tài)代理采用了FastClass機(jī)制,其分別為代理類和被代理類各生成一個(gè)FastClass,這個(gè)FastClass類會(huì)為代理類或被代理類的方法分配一個(gè) index(int類型)。這個(gè)index當(dāng)做一個(gè)入?yún)ⅲ現(xiàn)astClass 就可以直接定位要調(diào)用的方法直接進(jìn)行調(diào)用,這樣省去了反射調(diào)用,所以調(diào)用效率比 JDK 動(dòng)態(tài)代理通過反射調(diào)用更高。

但是我們看上面的源碼也可以明顯看到,JDK動(dòng)態(tài)代理只生成一個(gè)文件,而CGLIB生成了三個(gè)文件,所以生成代理對(duì)象的過程會(huì)更復(fù)雜。

兩者區(qū)別

  • JDK代理只能對(duì)實(shí)現(xiàn)接口的類生成代理;CGLib是針對(duì)類實(shí)現(xiàn)代理,對(duì)指定的類生成一個(gè)子類,并覆蓋其中的方法,這種通過繼承類的實(shí)現(xiàn)方式,不能代理final修飾的類。
  • JDK代理使用的是反射機(jī)制實(shí)現(xiàn)aop的動(dòng)態(tài)代理,CGLib代理使用字節(jié)碼處理框架ASM,通過修改字節(jié)碼生成子類。
  • JDK動(dòng)態(tài)代理機(jī)制是委托機(jī)制,具體說動(dòng)態(tài)實(shí)現(xiàn)接口類,在動(dòng)態(tài)生成的實(shí)現(xiàn)類里面委托hanlder去調(diào)用原始實(shí)現(xiàn)類方法,CGLib則使用的繼承機(jī)制,具體說被代理類和代理類是繼承關(guān)系,所以代理類是可以賦值給被代理類的,如果被代理類有接口,那么代理類也可以賦值給接口。
責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2022-09-01 10:40:29

SpringAOPJDK

2021-07-06 06:39:22

Java靜態(tài)代理動(dòng)態(tài)代理

2021-04-22 09:58:15

JDK代理動(dòng)態(tài)

2021-07-14 11:07:56

AOPJDKCglib

2025-02-27 00:32:35

2023-07-05 08:17:38

JDK動(dòng)態(tài)代理接口

2021-01-14 05:16:09

MyBatis動(dòng)態(tài)代理

2017-05-11 21:30:01

Android動(dòng)態(tài)代理ServiceHook

2024-01-04 07:42:44

JavaCGLIBJDK

2011-04-06 11:41:25

Java動(dòng)態(tài)代理

2024-09-05 09:35:58

CGLIBSpring動(dòng)態(tài)代理

2023-02-24 07:42:30

Java動(dòng)態(tài)代理

2022-02-22 22:44:46

接口源碼對(duì)象

2012-08-28 10:59:26

JavaJava動(dòng)態(tài)代理Proxy

2015-09-22 11:09:47

Java 8動(dòng)態(tài)代理

2011-03-23 10:40:51

java代理模式

2009-12-28 15:45:22

動(dòng)態(tài)網(wǎng)絡(luò)接入控制

2022-06-30 10:05:30

Java接口動(dòng)態(tài)代理

2020-12-29 05:34:00

動(dòng)態(tài)代理

2021-07-03 08:59:49

動(dòng)態(tài)代理JDK
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 中文字幕第一页在线 | 亚洲欧美日韩一区二区 | www久久 | 成人av播放| 老司机67194精品线观看 | 国产成人一区二区三区 | 精品久久久久久亚洲精品 | 一本一道久久a久久精品综合蜜臀 | 求个av网址| 最新中文字幕 | 99pao成人国产永久免费视频 | 黄网站免费在线 | 亚洲精品99999 | 视频一区二区三区在线观看 | 男人的天堂中文字幕 | 亚洲精品日韩综合观看成人91 | 秋霞电影一区二区 | a黄在线观看 | 欧美 日韩 综合 | 久久久国产精品 | 成人免费看黄 | 色黄爽 | 亚洲一区电影 | 在线观看成人 | 久久精品国产99国产 | 日韩视频一区二区三区 | 美女日批免费视频 | 久久免费精品 | 日本特黄a级高清免费大片 国产精品久久性 | 国产免费人成xvideos视频 | www.国产日本 | 中文字幕a√ | 黄色在线 | 精品一区二区三区四区五区 | 国产成人综合网 | 国产中文字幕在线观看 | 九九色九九 | 亚洲欧美国产精品久久 | 欧美一级在线观看 | 毛片久久久 | 91亚洲视频在线 |