從Mybatis源碼理解jdk動態代理默認調用invoke方法


一、背景
最近在工作之余,把mybatis的源碼看了下,決定自己手寫個簡單版的。實現核心的功能即可。寫完之后,執行了一下,正巧在mybatis對Mapper接口的動態代理這個核心代碼這邊發現一個問題。正好再回頭看下jdk的動態代理,才發現問題所在。

二、問題
當我用SqlSession.getMapper() 方法來獲取Mapper的代理類的時候,發現這個代理對象所展示的toString()是個null。如下圖

而debug了一下mybatis的源碼,發現是有值,並且的確是new 代理的目標對象為MapperProxy類型

三、回頭看jdk動態代理
當我在排查問題的時候,無意中發現,在執行(T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);方法時,竟然會拋出 mapperProxy類的invoke方法中的異常,但是這個時候程序還沒有走到任何代理的方法。
回頭找了下之前學着寫的動態代理的例子,並在invoke方法里面輸出了method。如下:

啟動main方法,發現打印的內容:

這時候才發現,在實例化代理類的時候,會調用一次invoke()方法,並且此時調用方法的method參數是Object.toString() 。看到這發現了兩點

  1. invoke方法在實例化代理的時候會調用一次,如果這個方法有對全局的公共變量做修改的話,會存在隱患的問題
  2. 代理類的toString 最后出來的類的名稱就是調用這個方法得到的。將代碼中result輸出就是對應的代理類。

四、發現並解決問題
回到自己的手寫的mybatis源碼中,自然就定位到了如下這個地方:

對比一下mybatis的源碼

 

正是紅框中的代碼,自己手寫的時候認為代理的方法的聲明類都是定義的mapper接口,這邊的判斷其實沒有必要,也走不到。然而從第三點中可以知道,在new 代理類的時候傳入的Method為toString方法正好進了這個分支,並且調用了當前MapperProxy實例的toString方法,返回了代理類的名稱,正是之前所缺失的。把這段代碼加上就OK了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM