首頁>技術>

關於這個問題,我之前面試過一些人,很多人是這麼回答的:

1.我領導叫我們使用Mybatis,大家都這麼用就這麼用了(沒想過,反正就這麼用)。

2.雖然我不知道具體是怎麼實現的,但我覺得肯定是……(此處略去若干的漫天猜想),但是也不對啊,難道是……(再次略去若干似懂非懂)。

3.使用動態代理實現的(然後就沒有下文了)。

對於上面的三種回答,前面兩種我們就沒必要往下聊了。

但是第三種回答,就有必要往下問:那你說說動態代理有哪些實現方式?Mybatis使用的是哪一種?

如果這個問題你還能回答上來,那麼還會繼續問:UserMapper.java中大方法能不能過載?

如果你能回答上面的問題,本文就沒必要往下看了,已經不適合你了。

問題分析

先來看一張圖,這圖裡的程式碼就是我們前面寫的demo:

為什麼一個介面就能和一個xml檔案給繫結的呢?這就是今天我們要聊的話題。

可能很多小夥伴不熟悉ibatis,2010年之前,還沒有Mybatis,之後ibatis便成了現在的Mybatis,如果有興趣的朋友,可以看到Mybatis中的包目錄。

這個包目錄中就還是ibatis,並且ibatis的作者現在就在騰訊上班,開發英雄聯盟LOL。

如果有騰訊的小夥伴可以打聽打聽哈,大佬就在身邊。言歸正傳。

Mapper層在Mybatis中現在是介面形式就搞定了,而在ibatis時代還是必須要有實現類的,我記得2012年的時候,使用的就是ibatis,Dao(Mapper)必須要有實現類。

下面我們就來看看Mybatis中是怎麼做的。

使用案例

繼續使用我們上一節中的程式碼。

controller

service實現類中

打一個斷點,然後使用debug模式啟動專案。並訪問:

http://localhost:9002/test

userMapper=org.apache.ibatis.binding.MapperProxy@6da21078

發現Mybatis給UserMapper.java生成了一個代理物件,並且從名字上可以看出是JDK動態代理。

關於動態代理請,這裡我推薦我之前寫過的一篇文章:

https://gitbook.cn/m/mazi/activity/5d44e35e4fbf44126135c292?sut=c93c00a03b4f11eba07ad99b4dfbdab0&utm_source=chatweixinshare

其實,又差不多回到了ibatis時代,只是Mybatis中是透過動態代理的方式生成的代理類不是我們開發的,而是透過JDK動態代理生成的代理類。

下面我們也使用JDK動態代理來模擬一把。

import com.tian.mybatis.entity.User;import com.tian.mybatis.mapper.UserMapper;public class TestProxy {    public static void main(String[] args) {        MapperProxy proxy = new MapperProxy();        UserMapper mapper = proxy.newInstance(UserMapper.class);        User user = mapper.selectById(999);        System.out.println(user);        System.out.println(mapper.toString());    }}

輸出

但是在Mybatis中,遠遠不是這麼簡單的,但是本質就是這樣的。

下面我們就來大致分析一下Mybatis中的這個流程。

介面Mapper內的方法能過載嗎?

類似下面:

public User getUserById(Integer id);public User getUserById(Integer id, String name);

答案:不能

因為Mybatis中是使用package+Mapper+method全限名作為key,去xml內尋找唯一sql來執行的。

類似:key=com.tian.mybatis.UserMapper.getUserById,那麼,過載方法時將導致矛盾。

對於Mapper介面,Mybatis禁止方法過載(overLoad) 。

在MapperMethod類的靜態內部類中SqlCommand中有個resolveMappedStatement方法。

在Configuration中有個屬性,就是專案啟動的時候,會把Mapper.xml中資訊解析到這個屬性裡,以我們指定的namespace+method作為key放到Map裡面,後面我們呼叫Mapper介面動態類的某個方法時候再去map獲取。

protected final Map<String, MappedStatement> mappedStatements 

就是使用類的全路徑名.方法作為key存放到Map中的。

總結

常用動態代理方式:JDK動態代理和CGlib動態代理。

Mybatis是採用JDK動態代理+反射+xml來解決介面繫結的,為我們建立可以呼叫的代理物件。

我們的Mapper中的方法是絕對不能過載的。

15
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Mysql五:資料庫、表結構、表資料的增加、刪除、修改