摘要:動態地代理,可以猜測一下它的含義,在運行時動態地對某些東西代理,代理它做了其他事情。所以動態代理的內容重點就是這個。所以下一篇我們來細致了解下的到底是怎么使用動態代理的。
之前講了《零基礎帶你看Spring源碼——IOC控制反轉》,本來打算下一篇講講Srping的AOP的,但是其中會涉及到Java的動態代理,所以先多帶帶一篇來了解下Java的動態代理到底是什么,Java是怎么實現它的。
動態代理看起來好像是個什么高大上的名詞,但其實并沒有那么復雜,直接從字面就很容易理解。動態地代理,可以猜測一下它的含義,在運行時動態地對某些東西代理,代理它做了其他事情。先不去搞清楚這個動態代理真正的含義,我們來舉個生動的例子來理解下它到底做了什么。
一個例子一個程序員Developer,他會開發code,他調試debug。
程序員有很多分類,其中有Java程序員JavaDeveloper,他會開發Java代碼,會調試Java代碼。
但是呢,有個叫Zack的程序員它在開發之前,會祈禱一下,這樣他開發的代碼就不會有bug。
Zack的這種“特異功能”是后天練出來的,并沒有哪種程序員有這種特性。雖然我們也可以定義一個擁有這樣特性的程序員,但是擁有各種亂七八糟特性的程序千千萬。我們什么時候才能定義完,而能保證不漏呢?
其實我們沒有必要去定義他,因為他是后天養成的,我們應該在這個程序員的成長期去實現這個特性,而不是在他出生之前定義。
我們來看下代碼是怎么實現的
如果Zack只是一個普通的Java程序員,那么他的開發結果是
Zack is coding java
Zack is debugging java
但是真正的Zack(代理后)
Zack is praying for the code!
Zack is coding java
Zack"s have no bug!No need to debug!
回看下上面是如何使用動態代理的使用。生成一個實例對象,然后用Proxy的newInstance方法對這個實例對象代理生成一個代理對象。
這里有一個非常關鍵的人,也是比較少人去理解它的。為什么要傳zack的類加載和zack的接口呢?
有沒有留意到zackProxy的類型是Developer接口,而不是一個實現類。因為zack在被代理后生成的對象,并不屬于Developer接口的任何一個實現類。但是它是基于Developer接口和zack的類加載代理出來的。
看下newProxyInstance()的接口定義
這三個參數具體的含義來看看注解是怎么描述的
loder,選用的類加載器。因為代理的是zack,所以一般都會用加載zack的類加載器。
interfaces,被代理的類所實現的接口,這個接口可以是多個。
h,綁定代理類的一個方法。
loder和interfaces基本就是決定了這個類到底是個怎么樣的類。而h是InvocationHandler,決定了這個代理類到底是多了什么功能。所以動態代理的內容重點就是這個InvocationHandler。
InvocationHandler
根據注解描述可知,InvocationHandler作用就是,當代理對象的原本方法被調用的時候,會綁定執行一個方法,這個方法就是InvocationHandler里面定義的內容,同時會替代原本方法的結果返回。
InvocationHandler接收三個參數
proxy,代理后的實例對象。
method,對象被調用方法。
args,調用時的參數。
在上面的例子里,
如果最后的return語句改成
return method.invoke(proxy, agrs);
invoke的對象不是zack,而是proxy,根據上面的說明猜猜會發生什么?
是的,會不停地循環調用。因為proxy是代理類的對象,當該對象方法被調用的時候,會觸發InvocationHandler,而InvocationHandler里面又調用一次proxy里面的對象,所以會不停地循環調用。并且,proxy對應的方法是沒有實現的。所以是會循環的不停報錯
通過上面的講解,相信大家對動態代理的使用理解得比較深刻了。那動態代理到底是怎么實現的呢,我們來看看源碼其中關鍵的地方。
在newProxyInstance()發放中有這樣幾段。
其實大概就是把接口復制出來,通過這些接口和類加載器,拿到這個代理類cl。然后通過反射的技術復制拿到代理類的構造函數(這部分代碼在Class類中的getConstructor0方法),最后通過這個構造函數new個一對象出來,同時用InvocationHandler綁定這個對象。
動態代理的好處我們從例子就能看出來,它比較靈活,可以在運行的時候才切入改變類的方法,而不需要預先定義它。
動態代理一般我們比較少去手寫,但我們用得其實非常多。在Spring項目中用的注解,例如依賴注入的@Bean、@Autowired,事務注解@Transactional等都有用到,換言之就是Srping的AOP(切面編程)。
這種場景的使用是動態代理最佳的落地點,可以非常靈活地在某個類,某個方法,某個代碼點上切入我們想要的內容,就是動態代理其中的內容。所以下一篇我們來細致了解下Spring的AOP到底是怎么使用動態代理的。
如果覺得還不錯,請關注公眾號:Zack說碼
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/77106.html
摘要:,,面向切面編程。,切點,切面匹配連接點的點,一般與切點表達式相關,就是切面如何切點。例子中,注解就是切點表達式,匹配對應的連接點,通知,指在切面的某個特定的連接點上執行的動作。,織入,將作用在的過程。因為源碼都是英文寫的。 之前《零基礎帶你看Spring源碼——IOC控制反轉》詳細講了Spring容器的初始化和加載的原理,后面《你真的完全了解Java動態代理嗎?看這篇就夠了》介紹了下...
摘要:序列化機制使得對象可以脫離程序的運行而獨立存在。普通序列化接口是一個標記接口,不用實現任何方法。如果此對象已經序列化過,則直接輸出編號即可。圖示上述序列化過程。一、序列化的含義、意義及使用場景二、序列化實現的方式1、Serializable1.1 普通序列化1.2 成員是引用的序列化1.3 同一對象序列化多次的機制1.4 java序列化算法潛在的問題1.5 可選的自定義序列化2、Extern...
摘要:如果遇到非常的復雜的匹配,正則表達式的優勢就更加明顯了。關于正則表達式書寫規則,可查看,上面說的很清楚了,我就不貼出來了。替換與正則表達式匹配的子串,并返回替換后的字符串。結語正則表達式并不難,懂了其中的套路之后,一切都變得簡單了。 前言 在正文開始前,先說說正則表達式是什么,為什么要用正則表達式?正則表達式在我個人看來就是一個瀏覽器可以識別的規則,有了這個規則,瀏覽器就可以幫我們判斷...
摘要:手動創建執行線程存在以上問題,而線程池就是用來解決這些問題的。線程池詳解上面我們已經知道了線程池的作用,而對于這樣一個好用,重要的工具,當然已經為我們提供了實現,這也是本篇文章的重點。,線程池一旦空閑超過時間,線程都將被回收。 showImg(https://segmentfault.com/img/remote/1460000018476903); 本文原創地址,我的博客:https...
摘要:從入門到放棄是什么,黑歷史,不講,自己百度去。類你沒有看錯,這里面的就沒有問題的。之前我們用過,和有了,再也不用這兩個貨了。一個函數,可以遍歷狀態感覺就是狀態機,好吧不說了再說就懵逼了。 ES6從入門到放棄 1.ES6是什么,黑歷史,不講,自己百度去。 2.在瀏覽器中如何使用? 1.babel babeljs.io在線編譯 2.traceur-----Google出的編譯器,把E...
閱讀 1307·2019-08-30 15:44
閱讀 1979·2019-08-30 13:49
閱讀 1651·2019-08-26 13:54
閱讀 3484·2019-08-26 10:20
閱讀 3239·2019-08-23 17:18
閱讀 3293·2019-08-23 17:05
閱讀 2129·2019-08-23 15:38
閱讀 1012·2019-08-23 14:35