亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

Java的動態代理機制詳解

2019-11-06 06:43:34
字體:
來源:轉載
供稿:網友

學習java的同學注意了!?。?nbsp;學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入Java學習交流群,群號碼:523047986  我們一起學Java!

在學習SPRing的時候,我們知道Spring主要有兩大思想,一個是IoC,另一個就是AOP,對于IoC,依賴注入就不用多說了,而對于Spring的核心AOP來說,我們不但要知道怎么通過AOP來滿足的我們的功能,我們更需要學習的是其底層是怎么樣的一個原理,而AOP的原理就是java的動態代理機制,所以本篇隨筆就是對java的動態機制進行一個回顧。

在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{    @Override    public void rent()    {        System.out.println("I want to rent my house");    }        @Override    public 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;    }        @Override    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;    }}復制代碼

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

復制代碼
public class Client{    public static void main(String[] args)    {        //    我們要代理的真實對象        Subject realSubject = new RealSubject();        //    我們要代理哪個真實對象,就將該對象傳進去,最后是通過該真實對象來調用其方法的        InvocationHandler handler = new DynamicProxy(realSubject);        /*         * 通過Proxy的newProxyInstance方法來創建我們的代理對象,我們來看看其三個參數         * 第一個參數 handler.getClass().getClassLoader() ,我們這里使用handler這個類的ClassLoader對象來加載我們的代理對象         * 第二個參數realSubject.getClass().getInterfaces(),我們這里為代理對象提供的接口是真實對象所實行的接口,表示我要代理的是該真實對象,這樣我就能調用這組接口中的方法了         * 第三個參數handler, 我們這里將這個代理對象關聯到了上方的 InvocationHandler 這個對象上         */        Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject                .getClass().getInterfaces(), handler);                System.out.println(subject.getClass().getName());        subject.rent();        subject.hello("world");    }}復制代碼

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

復制代碼
$Proxy0before rent houseMethod:public abstract void com.xiaoluo.dynamicproxy.Subject.rent()I want to rent my houseafter rent housebefore rent houseMethod:public abstract void com.xiaoluo.dynamicproxy.Subject.hello(java.lang.String)hello: worldafter 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其就是通過動態代理的機制實現的,所以我們必須要好好的理解動態代理的機制。

學習Java的同學注意了?。?! 學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入Java學習交流群,群號碼:523047986  我們一起學Java!


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
狠狠躁夜夜躁人人躁婷婷91| 亚洲xxxx18| 国产亚洲精品久久久| 亚洲综合成人婷婷小说| 精品成人乱色一区二区| 亚洲一区二区福利| 国产日韩欧美黄色| 国产精品久久电影观看| 国产精品福利片| 美日韩在线视频| 亚洲一级一级97网| 国产精品高潮视频| 国产精品亚洲综合天堂夜夜| 国产精品老女人精品视频| 欧美成人激情视频| 日韩久久免费视频| 日韩av在线电影网| 亚洲一区www| 日韩av理论片| 91在线观看免费高清完整版在线观看| 性欧美亚洲xxxx乳在线观看| 国产午夜精品理论片a级探花| 91久久精品一区| 久久国产精品网站| 欧美老妇交乱视频| 日本欧美一二三区| 国产精品91视频| 精品丝袜一区二区三区| 亚洲国产精品va在线看黑人| 亚洲成人av资源网| 影音先锋欧美精品| 第一福利永久视频精品| 国产精品久久久久久久久久尿| 欧美激情视频播放| 中文字幕不卡av| 欧美裸体男粗大视频在线观看| 黑人巨大精品欧美一区二区| 91精品国产91久久久久久久久| 91网站在线免费观看| 91福利视频在线观看| 欧美高清在线视频观看不卡| 国产欧美日韩中文字幕| 中文字幕亚洲欧美日韩2019| 亚洲国产精品视频在线观看| 国产久一一精品| 欧美理论电影网| 亚洲a成v人在线观看| 欧美国产精品人人做人人爱| 久久精品国产一区| 亚洲精品在线91| 欧美丰满少妇xxxx| 国产精品久久久久免费a∨| 91亚洲精品一区二区| 亚洲bt欧美bt日本bt| 久久久噜噜噜久久久| 久久久综合免费视频| 久久久中精品2020中文| 日韩成人网免费视频| 亚洲色图校园春色| 中文字幕久精品免费视频| 国产成人拍精品视频午夜网站| 亚洲综合大片69999| 欧美一级大片在线免费观看| 中文字幕视频在线免费欧美日韩综合在线看| 欧美性猛交xxxx富婆| 欧美二区乱c黑人| 美日韩在线视频| 久久国产精品久久久久久| 精品久久久在线观看| 国产精品久久97| 97视频在线播放| 欧美国产欧美亚洲国产日韩mv天天看完整| 人人澡人人澡人人看欧美| 免费99精品国产自在在线| 777午夜精品福利在线观看| 亚洲乱码一区二区| 国产欧美精品在线播放| 久久国产精品久久精品| 亚洲欧美精品在线| 亚洲精品第一页| 夜夜嗨av色综合久久久综合网| 亚洲视频欧洲视频| 精品久久香蕉国产线看观看亚洲| 成人高清视频观看www| 国产精品视频网| 日韩电影在线观看中文字幕| 国产精品午夜一区二区欲梦| 国产主播精品在线| 91国语精品自产拍在线观看性色| 久久亚洲国产成人| 欧美成人午夜免费视在线看片| 精品久久久久久中文字幕| 精品成人久久av| 亚洲精品美女久久久久| 韩剧1988免费观看全集| 国产午夜精品全部视频播放| 久久久久久久999精品视频| 最近中文字幕mv在线一区二区三区四区| 日韩一级黄色av| 日韩一区视频在线| 夜夜嗨av一区二区三区免费区| 国产精品免费久久久久久| 日韩av在线免播放器| 欧美性猛交xxxx乱大交蜜桃| 国产精品一区二区久久久| 精品久久久久久久久久久久久久| 亚洲精品国产美女| 亚洲国产中文字幕久久网| 日韩欧美在线观看视频| 亚洲精品自在久久| 久久成年人免费电影| 欧美日韩国产成人| 一二美女精品欧洲| 欧美日韩免费区域视频在线观看| 欧美日韩免费观看中文| 中文字幕亚洲欧美| 国产精品久久久久久久久借妻| 成人久久18免费网站图片| 精品久久久久久国产91| 国产精品日韩在线一区| 97色在线观看免费视频| 国产精品夜色7777狼人| 成人国内精品久久久久一区| 97人人模人人爽人人喊中文字| 国产精品久久网| 91在线免费视频| 欧美在线视频免费| 国内精品美女av在线播放| 国产精选久久久久久| 最好看的2019年中文视频| 欧美激情在线视频二区| 九九热视频这里只有精品| 亚洲免费视频网站| 欧美激情精品久久久久久免费印度| 欧美成人合集magnet| 国产一区二区丝袜高跟鞋图片| 国产伦精品一区二区三区精品视频| 日韩电影第一页| 国产精品爽黄69天堂a| 九九久久久久99精品| 国产精品久久久久久久久久新婚| 97婷婷涩涩精品一区| 亚洲精品白浆高清久久久久久| 中文字幕亚洲国产| 91精品国产色综合久久不卡98| 亚洲一区二区自拍| 97久久国产精品| 国产一区二区三区在线免费观看| 欧美日韩免费网站| 亚洲欧美另类在线观看| 高跟丝袜一区二区三区| 成人在线视频福利| 成人午夜小视频| 国产91精品青草社区| 亚洲精品少妇网址| 久久久伊人日本| 国产丝袜一区二区三区免费视频| 日韩欧美中文免费| 夜色77av精品影院| 中文字幕综合在线| 91av免费观看91av精品在线| 久国内精品在线| 欧美成人精品xxx| 国产精品网红福利|