1. 程式人生 > >mybatis動態代理

mybatis動態代理

ati csdn delet command ret mybatis框架 bat load div

(很早就接觸了動態代理,出於不知道這種模式的實用意義到底在哪裏,所以每次簡單了解完代理的過程不久也忘了。但是知道了mybatis就是利用動態代理來生成mapper實例,借此再總結一次)

JDK動態代理只能針對接口(所以聲明Mapper接口),如果要針對普通類則可以考慮CGLib的實現。

平時使用mybatis基本都是使用接口聲明,然後註入直接調用接口方法,即可完成數據庫操作。有沒有疑惑過,為什麽沒看到實現該接口的類,就可以調用方法。要知道接口是不能實例化的。這是對代理類生成(代理模式)的理解。

對於常規Java類變量的創建要求有 .java 文件,然後編譯成 .class 文件,然後虛擬機加載該 .class 文件,最後才能生成對象。

但是對Subject proxyInstance(某個代理實例)該代理類其是不存在 .java 文件的,也就是該對象的 .class 文件是動態生成的,然後虛擬機加載該class文件,然後創建對象。


可知JDK動態代理需要接口,真實實現類,Client調用方。在常規的Mybatis的Mapper代理中接口就是Mapper,Client是service,那麽真實的實現類是什麽?

這裏就是Mapper代理的關鍵點。

從關鍵的部分開始解讀源碼:

1、MapperRegistry(Mapper註冊器)
MapperRegistry類是註冊Mapper接口與獲取代理類實例的工具類。
該工具類裏頭有很明顯的執行鏈:


首先是addMappers(String packageName)方法,該方法通過包名掃描下面所有接口。
該方法內就是對addMappers(重載方法)的調用,該方法只是個中間過程,方法內通過循環執行addMapper(mapperClass)方法。
addMapper對每一個掃描到的接口( if (type.isInterface()) ,接口類也是Class類型,編譯後也會生成相應的.class文件 )放進knownMappers
中,knownMappers是一個HashMap,Key是mapper的類型對象, Value是MapperProxyFactory對象。
接著(某處?)調用getMapper方法,方法裏面最後會去調用MapperProxyFactory類的newInstance方法。getMapper方法前會初始化

MapperProxyFactory,它是創建Mapper代理對象的工廠。

@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    //通過Mapper的接口類型 去Map當中查找 如果為空就拋異常
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null)
        throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    try {
       //否則創建一個當前接口的代理對象 並且傳入sqlSession
        return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
        throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
}                        


2、MapperProxyFactory(創建Mapper代理對象的工廠)
該工廠內有兩個同名的重載方法,執行鏈是先通過newInstance(SqlSession sqlSession)方法獲得上方所說的真實的實現類mapperProxy,去調用
newInstance(MapperProxy<T> mapperProxy)方法。最後就是一直以來所熟悉的的JDK動態代理return (T) Proxy.newProxyInstance
(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
所以重點回到獲得真實的實現類MapperProxy上

3、MapperProxy(mapper的實際代理對象)
這個類實現了JDK的動態代理接口InvocationHandler。
該類中有一個methodCache對象,是接口中方法的緩存。
從上方第一點的getMapper方法就是用來獲得相關的數據操作類接口。而事實數據操作類邦定了動態代理。所以操據操作類執行方法的時候,會觸動
每個方法相應的MapperProxy類的invoke方法。
該方法從緩存中獲得MapperMethod實例,通過mapperMethod.execute(sqlSession, args)真正對一個方法執行,可以看出這個方法對才是真正對
SqlSession進行的包裝調用。


4、MapperMethod是真正代理一條mybatis mapper標簽的方法,要知道動態代理只是對一個方法作代理。
類裏面有倆個成員:SqlCommand類和MethodSignature類。一個跟SQL語句有關系,一個跟要執行的方法有關系。
並使用一個內部類SqlCommand來封裝底層的增刪改查操作,確切來講這一部分的內容跟XxxMapper的XML配置文件裏面的select節點、delete節點等
有關。我們都會知道節點上有id屬性值。那麽MyBatis框架會把每一個節點(如:select節點、delete節點)生成一個MappedStatement類。要找到
MappedStatement類就必須通過id來獲得。

參考:

https://blog.csdn.net/lom9357bye/article/details/80207074
https://blog.csdn.net/xiaokang123456kao/article/details/76228684

mybatis動態代理