日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

关于动态代理详解

發布時間:2025/6/15 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 关于动态代理详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

關于動態代理詳解

轉載聲明:本文轉載至http://www.cnblogs.com/xiaoluo501395377/p/3383130.html 一、動態代理與靜態代理的區別。 (1)Proxy類的代碼被固定下來,不會因為業務的逐漸龐大而龐大; (2)可以實現AOP編程,這是靜態代理無法實現的; (3)解耦,如果用在web業務下,可以實現數據層和業務層的分離。 (4)動態代理的優勢就是實現無侵入式的代碼擴展。 靜態代理這個模式本身有個大問題,如果類方法數量越來越多的時候,代理類的代碼量是十分龐大的。所以引入動態代理來解決此類問題 二、動態代理

在java的動態代理機制中,有兩個重要的類或接口,一個是 InvocationHandler(Interface)、另一個則是 Proxy(Class),這一個類和接口是實現我們動態代理所必須用到的。首先我們先來看看java的API幫助文檔是怎么樣對這兩個類進行描述的:

InvocationHandler:

InvocationHandler is the interface implemented by the invocation handler of a proxy instance. Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

每一個動態代理類都必須要實現InvocationHandler這個接口,并且每個代理類的實例都關聯到了一個handler,當我們通過代理對象調用一個方法的時候,這個方法的調用就會被轉發為由InvocationHandler這個接口的 invoke 方法來進行調用。我們來看看InvocationHandler這個接口的唯一一個方法?invoke?方法:

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

我們看到這個方法一共接受三個參數,那么這三個參數分別代表什么呢?

Object invoke(Object proxy, Method method, Object[] args) throws Throwableproxy:  指代我們所代理的那個真實對象 method:  指代的是我們所要調用真實對象的某個方法的Method對象 args:  指代的是調用真實對象某個方法時接受的參數

如果不是很明白,等下通過一個實例會對這幾個參數進行更深的講解。

接下來我們來看看Proxy這個類:

Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.

Proxy這個類的作用就是用來動態創建一個代理對象的類,它提供了許多的方法,但是我們用的最多的就是?newProxyInstance?這個方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.

這個方法的作用就是得到一個動態的代理對象,其接收三個參數,我們來看看這三個參數所代表的含義:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentExceptionloader:  一個ClassLoader對象,定義了由哪個ClassLoader對象來對生成的代理對象進行加載interfaces:  一個Interface對象的數組,表示的是我將要給我需要代理的對象提供一組什么接口,如果我提供了一組接口給它,那么這個代理對象就宣稱實現了該接口(多態),這樣我就能調用這組接口中的方法了h:  一個InvocationHandler對象,表示的是當我這個動態代理對象在調用方法的時候,會關聯到哪一個InvocationHandler對象上

?

好了,在介紹完這兩個接口(類)以后,我們來通過一個實例來看看我們的動態代理模式是什么樣的:

首先我們定義了一個Subject類型的接口,為其聲明了兩個方法:

public interface Subject {public void rent();public void hello(String str); }

接著,定義了一個類來實現這個接口,這個類就是我們的真實對象,RealSubject類:

public class RealSubject implements Subject {@Overridepublic void rent(){System.out.println("I want to rent my house");}@Overridepublic void hello(String str){System.out.println("hello: " + str);} }

?

下一步,我們就要定義一個動態代理類了,前面說個,每一個動態代理類都必須要實現 InvocationHandler 這個接口,因此我們這個動態代理類也不例外:

public class DynamicProxy implements InvocationHandler {// 這個就是我們要代理的真實對象private Object subject;// 構造方法,給我們要代理的真實對象賦初值public DynamicProxy(Object subject){this.subject = subject;}@Overridepublic Object invoke(Object object, Method method, Object[] args)throws Throwable{// 在代理真實對象前我們可以添加一些自己的操作System.out.println("before rent house");System.out.println("Method:" + method);// 當代理對象調用真實對象的方法時,其會自動的跳轉到代理對象關聯的handler對象的invoke方法來進行調用 method.invoke(subject, args);// 在代理真實對象后我們也可以添加一些自己的操作System.out.println("after rent house");return null;}}

?

最后,來看看我們的Client類:

public class Client {public static void main(String[] args) {// 我們要代理的真實對象Subject realSubject = new RealSubject();//這里指定被代理類 // 我們要代理哪個真實對象,就將該對象傳進去,最后是通過該真實對象來調用其方法的InvocationHandler handler = new DynamicProxy(realSubject);/** 通過Proxy的newProxyInstance方法來創建我們的代理對象,我們來看看其三個參數 * 第一個參數 handler.getClass().getClassLoader(),我們這里使用代理類的類加載器,也就是被代理的那個真實對象* 第二個參數realSubject.getClass().getInterfaces(),我們這里為代理對象提供的接口是真實對象所實行的接口,表示我要代理的是該真實對象,這樣我就能調用這組接口中的方法了 * 第三個參數handler,我們這里將這個代理對象關聯到了上方的InvocationHandler 這個對象上*/Subject subject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),realSubject.getClass().getInterfaces(), handler);//這里可以通過運行結果證明subject是Proxy的一個實例,這個實例實現了Subject接口 System.out.println(subject instanceof Proxy); //這里可以看出subject的Class類是$Proxy0,這個$Proxy0類繼承了Proxy,實現了Subject接口 System.out.println("subject的Class類是:"+subject.getClass().toString()); System.out.print("subject中的屬性有:"); Field[] field=subject.getClass().getDeclaredFields(); for(Field f:field){ System.out.print(f.getName()+", "); } System.out.print("\n"+"subject中的方法有:"); Method[] method=subject.getClass().getDeclaredMethods(); for(Method m:method){ System.out.print(m.getName()+", "); } System.out.println("\n"+"subject的父類是:"+subject.getClass().getSuperclass()); System.out.print("\n"+"subject實現的接口是:"); Class<?>[] interfaces=subject.getClass().getInterfaces(); for(Class<?> i:interfaces){ System.out.print(i.getName()+", "); } System.out.println(subject.getClass().getName());System.out.println("\n\n"+"運行結果為:");subject.rent();subject.hello("world");} }

?

我們先來看看控制臺的輸出:

true subject的Class類是:class com.sun.proxy.$Proxy0 subject中的屬性有:m1, m4, m0, m3, m2, subject中的方法有:equals, toString, hashCode, rent, hello, subject的父類是:class java.lang.reflect.Proxysubject實現的接口是:com.emuii.proxy.Subject,
com.sun.proxy.$Proxy0 運行結果為: before rent house Method:
public abstract void com.emuii.proxy.Subject.rent() I want to rent my house after rent housebefore rent house Method:public abstract void com.emuii.proxy.Subject.hello(java.lang.String) hello: world after rent house

?

我們首先來看看?$Proxy0 這東西,我們看到,這個東西是由?System.out.println(subject.getClass().getName()); 這條語句打印出來的,那么為什么我們返回的這個代理對象的類名是這樣的呢?

Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler);

可能我以為返回的這個代理對象會是Subject類型的對象,或者是InvocationHandler的對象,結果卻不是,首先我們解釋一下為什么我們這里可以將其轉化為Subject類型的對象?原因就是在newProxyInstance這個方法的第二個參數上,我們給這個代理對象提供了一組什么接口,那么我這個代理對象就會實現了這組接口,這個時候我們當然可以將這個代理對象強制類型轉化為這組接口中的任意一個,因為這里的接口是Subject類型,所以就可以將其轉化為Subject類型了。

同時我們一定要記住,通過?Proxy.newProxyInstance 創建的代理對象是在jvm運行時動態生成的一個對象,它并不是我們的InvocationHandler類型,也不是我們定義的那組接口的類型,而是在運行是動態生成的一個對象,并且命名方式都是這樣的形式,以$開頭,proxy為中,最后一個數字表示對象的標號

接著我們來看看這兩句?

subject.rent();
subject.hello("world");

這里是通過代理對象來調用實現的那種接口中的方法,這個時候程序就會跳轉到由這個代理對象關聯到的 handler 中的invoke方法去執行,而我們的這個 handler 對象又接受了一個 RealSubject類型的參數,表示我要代理的就是這個真實對象,所以此時就會調用 handler 中的invoke方法去執行:

public Object invoke(Object object, Method method, Object[] args)throws Throwable{//  在代理真實對象前我們可以添加一些自己的操作System.out.println("before rent house");System.out.println("Method:" + method);// 當代理對象調用真實對象的方法時,其會自動的跳轉到代理對象關聯的handler對象的invoke方法來進行調用 method.invoke(subject, args);//  在代理真實對象后我們也可以添加一些自己的操作System.out.println("after rent house");return null;}

?

我們看到,在真正通過代理對象來調用真實對象的方法的時候,我們可以在該方法前后添加自己的一些操作,同時我們看到我們的這個 method 對象是這樣的:

public abstract void com.xiaoluo.dynamicproxy.Subject.rent()public abstract void com.xiaoluo.dynamicproxy.Subject.hello(java.lang.String)

正好就是我們的Subject接口中的兩個方法,這也就證明了當我通過代理對象來調用方法的時候,起實際就是委托由其關聯到的 handler 對象的invoke方法中來調用,并不是自己來真實調用,而是通過代理的方式來調用的。

這就是我們的java動態代理機制

?

本篇隨筆詳細的講解了java中的動態代理機制,這個知識點非常非常的重要,包括我們Spring的AOP其就是通過動態代理的機制實現的,所以我們必須要好好的理解動態代理的機制。

轉載于:https://www.cnblogs.com/lesliehe/p/7803388.html

總結

以上是生活随笔為你收集整理的关于动态代理详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。