以前講了《零基礎帶你看Spring源碼——IOC控制反轉》,原本打算下一篇講講Srping的AOP的,可是其中會涉及到Java的動態代理,因此先單獨一篇來了解下Java的動態代理究竟是什麼,Java是怎麼實現它的。java
動態代理看起來好像是個什麼高大上的名詞,但其實並無那麼複雜,直接從字面就很容易理解。動態地代理,能夠猜想一下它的含義,在運行時動態地對某些東西代理,代理它作了其餘事情。先不去搞清楚這個動態代理真正的含義,咱們來舉個生動的例子來理解下它到底作了什麼。程序員
一個程序員Developer,他會開發code,他調試debug。
程序員有不少分類,其中有Java程序員JavaDeveloper,他會開發Java代碼,會調試Java代碼。
可是呢,有個叫Zack的程序員它在開發以前,會祈禱一下,這樣他開發的代碼就不會有bug。spring
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!debug
回看下上面是如何使用動態代理的使用。生成一個實例對象,而後用Proxy的newInstance方法對這個實例對象代理生成一個代理對象。
這裏有一個很是關鍵的人,也是比較少人去理解它的。爲何要傳zack的類加載和zack的接口呢?
有沒有留意到zackProxy的類型是Developer接口,而不是一個實現類。由於zack在被代理後生成的對象,並不屬於Developer接口的任何一個實現類。可是它是基於Developer接口和zack的類加載代理出來的。3d
看下newProxyInstance()的接口定義
這三個參數具體的含義來看看註解是怎麼描述的
代理
loder和interfaces基本就是決定了這個類究竟是個怎麼樣的類。而h是InvocationHandler,決定了這個代理類究竟是多了什麼功能。因此動態代理的內容重點就是這個InvocationHandler。調試
根據註解描述可知,InvocationHandler做用就是,當代理對象的本來方法被調用的時候,會綁定執行一個方法,這個方法就是InvocationHandler裏面定義的內容,同時會替代本來方法的結果返回。
InvocationHandler接收三個參數
在上面的例子裏,
若是最後的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究竟是怎麼使用動態代理的。
更多技術文章、精彩乾貨,請關注
博客:zackku.com
微信公衆號:Zack說碼