亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java中的動(dòng)態(tài)代理使用

 更新時(shí)間:2024年07月12日 11:13:03   作者:讓你三行代碼QAQ  
這篇文章主要介紹了Java中的動(dòng)態(tài)代理使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

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

動(dòng)態(tài)代理的時(shí)候,定義一個(gè)接口,需要代理人和被代理類實(shí)現(xiàn)這個(gè)接口,這樣不夠靈活,代理類能夠代理的類只有實(shí)現(xiàn)這個(gè)接口的類。

非常不靈活,假如被代理人的類沒(méi)有實(shí)現(xiàn)這個(gè)接口,那么就需重新寫一個(gè)代理類。對(duì)于日志、事務(wù)這些操作是不區(qū)分業(yè)務(wù)的,即不需要規(guī)定都實(shí)現(xiàn)某接口。因此,出現(xiàn)了動(dòng)態(tài)代理

java種的動(dòng)態(tài)代理生成的方式大概有三種JDK動(dòng)態(tài)代理、instrument動(dòng)態(tài)代理、cglib動(dòng)態(tài)代理。其中,前兩種是JDK自帶的,cglib是需要第三方依賴使用的。

  • JDK動(dòng)態(tài)代理:在程序運(yùn)行的過(guò)程種動(dòng)態(tài)的生成代理類,這個(gè)代理類實(shí)現(xiàn)被代理類的接口,因此使用時(shí)候被代理類必須實(shí)現(xiàn)接口;
  • instrument動(dòng)態(tài)代理:是通過(guò)Class字節(jié)文件在加載至內(nèi)存的過(guò)程種添加攔截器,動(dòng)態(tài)的修改字節(jié)文件實(shí)現(xiàn)的;
  • cglib:在程序運(yùn)行的過(guò)程種動(dòng)態(tài)生成代理類,這個(gè)代理類是通過(guò)繼承被代理類實(shí)現(xiàn)的,因此不能代理被final修飾的類
  • JDK動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理的底層都是ASM;

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

先看這樣一個(gè)程序

/** 接口*/
public interface Mobile {
    void move();
}
/** 被代理類*/
public class Car implements Mobile{
    @Override
    public void move() {
        System.out.println("move...");
    }
}
/** 使用動(dòng)態(tài)代理*/
public class Test {
    public static void main(String[] args) {
        Car car = new Car();
        System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles",true);
        Mobile proxyInstance = (Mobile) Proxy.newProxyInstance(Car.class.getClassLoader(), Car.class.getInterfaces(),  new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                long before = System.currentTimeMillis();
                System.out.println(method.getName()+"方法被執(zhí)行前。。。");
                Object invoke = method.invoke(car, args);
                System.out.println(method.getName()+"方法被執(zhí)行后。。。");
                long after = System.currentTimeMillis();
                System.out.println("耗時(shí):" + (after - before));
                return null;
            }
        });

        proxyInstance.move();
    }
}

創(chuàng)建代理類需要調(diào)用Proxy.newProxyInstance()方法,其中有三個(gè)參數(shù)

  • 第一個(gè)參數(shù):一個(gè)類加載器,一般使用被代理類的類加載器
  • 第二個(gè)參數(shù):被代理類實(shí)現(xiàn)的接口
  • 第三個(gè)參數(shù):一個(gè)InvocationHandler接口的實(shí)現(xiàn)類

可以把動(dòng)態(tài)代理的創(chuàng)建改成這樣:自己寫一個(gè)類實(shí)現(xiàn)InvocationHandler。

public class Test {
    public static void main(String[] args) {
        Car car = new Car();
        System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
        Mobile proxyInstance = (Mobile) Proxy.newProxyInstance(Car.class.getClassLoader(), Car.class.getInterfaces(), new MyInvocationHandler(car));
        proxyInstance.move();
    }

}
class MyInvocationHandler implements InvocationHandler{
    private Car car;

    public MyInvocationHandler(Car car) {
        this.car = car;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long before = System.currentTimeMillis();
        System.out.println(method.getName()+"方法被執(zhí)行前。。。");
        Object invoke = method.invoke(car, args);
        System.out.println(method.getName()+"方法被執(zhí)行后。。。");
        long after = System.currentTimeMillis();
        System.out.println("耗時(shí):" + (after - before));
        return null;
    }
}

要想搞懂JDK動(dòng)態(tài)代理必須查看動(dòng)態(tài)生成代理類,通過(guò)設(shè)置JDK動(dòng)態(tài)代理生成的類是否保存的一個(gè)屬性將生成的代理類保存下來(lái),通過(guò)在程序啟動(dòng)前加上: 

System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles",true);

代理類的調(diào)用過(guò)程

  • 生成的代理類
public final class $Proxy0 extends Proxy implements Mobile {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void move() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.shaoby.basic.proxy.JdkProxy.Mobile").getMethod("move");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
  • 可以看到代理類繼承了Proxy,并實(shí)現(xiàn)了我們定義的Mobile接口
  • 構(gòu)造方法傳入InvocationHandler類型,并賦值給父類Proxy中的h參數(shù),可以猜測(cè)這個(gè)就在獲取代理類時(shí)候的第三個(gè)參數(shù);
  • 代理類中通過(guò)反射生成了四個(gè)方法,除了Object中的equals、toString、hashCode外另外一個(gè)就是我們要代理的方法move;
  • 在move方法中調(diào)用了 super.h.invoke(this, m3, (Object[])null),即MyInvocationHandler中的invoke方法。
  • 因此在調(diào)用代理類的invoke方法時(shí),調(diào)用的就是MyInvocationHandler中的invoke方法。

Method類

這個(gè)類是一個(gè)方法的類,說(shuō)白了就是方法的模板,在這個(gè)類中有一個(gè)方法invoke,傳入兩個(gè)參數(shù),一個(gè)是調(diào)用方法的對(duì)象,另一個(gè)是方法的入?yún)?/p>

InvocationHandler中的invoke方法

可以看到在代理類中invoke方法的調(diào)用為 super.h.invoke(this, m3, (Object[])null);

MyInvocationHandler中的invoke方法:

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long before = System.currentTimeMillis();
        System.out.println(method.getName()+"方法被執(zhí)行前。。。");
        Object invoke = method.invoke(car, args);
        System.out.println(method.getName()+"方法被執(zhí)行后。。。");
        long after = System.currentTimeMillis();
        System.out.println("耗時(shí):" + (after - before));
        return null;
    }

參數(shù):

  • 第一個(gè)參數(shù):this,即代理類本身
  • 第二個(gè)參數(shù):m3,即move方法
  • 第三個(gè)參數(shù):第二個(gè)方法的入?yún)?/li>

返回值:

這個(gè)返回值其實(shí)是被代理方法的返回值,如果沒(méi)有返回值就返回null;

這里最重要的是method.invoke(car, args),就是用car對(duì)象調(diào)用move方法。

ASM

在上述分析中,動(dòng)態(tài)代理類的構(gòu)造方法中參數(shù)是我們猜測(cè)的。其實(shí)這里是用ASM實(shí)現(xiàn)的。在生成代理類時(shí)調(diào)用的Proxy.newInstance()傳入了InvocationHandler接口的實(shí)現(xiàn)類,Proxy.neInstance()會(huì)動(dòng)態(tài)的生成代理類,并產(chǎn)生一個(gè)代理對(duì)象。這里后續(xù)再研究。

ASM是Java字節(jié)碼操控框架,它能夠以二進(jìn)制形式修改已有類,或動(dòng)態(tài)生成類,ASM 可以直接產(chǎn)生二進(jìn)制 class 文件,也可以在類被加載入 Java 虛擬機(jī)之前動(dòng)態(tài)改變類行為。ASM 從類文件中讀入信息后,能夠改變類行為,分析類信息,甚至能夠根據(jù)用戶要求生成新類。

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

public class Test {

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Plane.class);
        enhancer.setCallback(new MyMethodInterceptor());
        Plane o = (Plane)enhancer.create();
        o.move();


    }
}
class MyMethodInterceptor implements MethodInterceptor{
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        long before = System.currentTimeMillis();
        System.out.println(method.getName()+"方法被執(zhí)行前。。。");
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println(method.getName()+"方法被執(zhí)行后。。。");
        long after = System.currentTimeMillis();
        System.out.println("耗時(shí):" + (after - before));
        return result;
    }
}

cglib動(dòng)態(tài)代理的原理是:

  • 指定代理類的父類
  • 生成代理類
  • 調(diào)用代理類父類的method

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • MyBatisPlus3如何向數(shù)據(jù)庫(kù)中存入List

    MyBatisPlus3如何向數(shù)據(jù)庫(kù)中存入List

    本文主要介紹了Mybatis Plus的類型處理器的使用,通過(guò)User.java和UserMapper.xml示例進(jìn)行詳細(xì)的解析,并提供了JSON解析器的使用方法,希望通過(guò)這篇文章,可以幫助大家更好的理解和掌握Mybatis Plus的類型處理器
    2024-10-10
  • 詳解在springmvc中解決FastJson循環(huán)引用的問(wèn)題

    詳解在springmvc中解決FastJson循環(huán)引用的問(wèn)題

    本篇文章主要介紹了在springmvc中解決FastJson循環(huán)引用的問(wèn)題,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-01-01
  • Spring Boot 使用Druid詳解

    Spring Boot 使用Druid詳解

    本篇文章主要介紹了Spring Boot 使用Druid配置詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-05-05
  • JAVA?POI設(shè)置EXCEL單元格格式用法舉例

    JAVA?POI設(shè)置EXCEL單元格格式用法舉例

    這篇文章主要給大家介紹了關(guān)于JAVA?POI設(shè)置EXCEL單元格格式用法的相關(guān)資料,POI中可能會(huì)用到一些需要設(shè)置EXCEL單元格格式的操作,需要的朋友可以參考下
    2023-08-08
  • java socket 詳細(xì)介紹

    java socket 詳細(xì)介紹

    本篇文章小編為大家介紹,java socket 詳細(xì)介紹。需要的朋友參考下
    2013-04-04
  • IntelliJIDEA中實(shí)現(xiàn)SpringBoot多實(shí)例運(yùn)行的兩種方式

    IntelliJIDEA中實(shí)現(xiàn)SpringBoot多實(shí)例運(yùn)行的兩種方式

    在微服務(wù)開發(fā)中,經(jīng)常需要同時(shí)啟動(dòng)多個(gè)服務(wù)實(shí)例進(jìn)行測(cè)試或模擬集群環(huán)境,?IntelliJ?IDEA?作為Java開發(fā)者常用工具,提供了靈活的多實(shí)例啟動(dòng)支持,本文將詳細(xì)介紹如何通過(guò)修改配置?和批量啟動(dòng)?兩種方式實(shí)現(xiàn)SpringBoot多實(shí)例運(yùn)行,并解決常見問(wèn)題,需要的朋友可以參考下
    2025-03-03
  • java 動(dòng)態(tài)生成SQL的實(shí)例講解

    java 動(dòng)態(tài)生成SQL的實(shí)例講解

    下面小編就為大家?guī)?lái)一篇java 動(dòng)態(tài)生成SQL的實(shí)例講解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-07-07
  • spring mvc4中相關(guān)注解的詳細(xì)講解教程

    spring mvc4中相關(guān)注解的詳細(xì)講解教程

    這篇文章主要給大家介紹了關(guān)于spring mvc4中相關(guān)注解的相關(guān)資料,其中詳細(xì)介紹了關(guān)于@Controller、@RequestMapping、@RathVariable、@RequestParam及@RequestBody等等注解的相關(guān)內(nèi)容,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-06-06
  • 使用IntelliJ IDEA查看類的繼承關(guān)系圖形(圖文詳解)

    使用IntelliJ IDEA查看類的繼承關(guān)系圖形(圖文詳解)

    這篇文章主要介紹了使用IntelliJ IDEA查看類的繼承關(guān)系圖形,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的工作或?qū)W習(xí)具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Java spring定時(shí)任務(wù)詳解

    Java spring定時(shí)任務(wù)詳解

    這篇文章主要為大家詳細(xì)介紹了Spring定時(shí)任務(wù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2021-10-10

最新評(píng)論