字數:2434,閱讀耗時:3分40秒。
老規矩,先上案例代碼,這樣大家可以更加熟悉是如何使用的,看過Mybatis系列的小夥伴,對這段代碼差不多都可以背下來了。
哈哈~,有點誇張嗎?不誇張的,就這行代碼。
看源碼有什麼用?
通過源碼的學習,我們可以收穫Mybatis的核心思想和框架設計,另外還可以收穫設計模式的應用。
前兩篇文章我們已經Mybatis配置文件解析到獲取SqlSession,下面我們來分析從SqlSession到userMapper:
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
前面那篇文章已經知道了這裡的sqlSession使用的是默認實現類DefaultSqlSession。所以我們直接進入DefaultSqlSession的getMapper方法。
這裡有三個問題:
問題1:getMapper返回的是個什麼對象?
上面可以看出,getMapper方法調用的是Configuration中的getMapper方法。然後我們進入Configuration中
這裡也沒做什麼,繼續調用MapperRegistry中的getMapper:
MapperProxyFactory對象裡保存了mapper接口的class對象,就是一個普通的類,沒有什麼邏輯。
在MapperProxyFactory類中使用了兩種設計模式:
單例模式methodCache(註冊式單例模式)。工廠模式getMapper()。繼續看MapperProxyFactory中的newInstance方法。
從代碼中可以看出,依然是穩穩的基於 JDK Proxy 實現的,而 InvocationHandler 參數是 MapperProxy 對象。
//UserMapper 的類加載器 //接口是UserMapper //h是mapperProxy對象 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h){ }
問題2:為什麼就可以調用他的方法?
上面調用newInstance方法時候創建了MapperProxy對象,並且是當做newProxyInstance的第三個參數,所以MapperProxy類肯定實現了InvocationHandler。
進入MapperProxy類中:
也就是說,getMapper方法返回的是一個JDK動態代理對象(類型是$Proxy+數字)。這個代理對象會繼承Proxy類,實現被代理的接口UserMpper,裡面持有了一個MapperProxy類型的觸發管理類。
當我們調用UserMpper的方法時候,實質上調用的是MapperProxy的invoke方法。
userMapper=$Proxy6@2355。
為什麼要在MapperRegistry中保存一個工廠類?
原來他是用來創建並返回代理類的。這裡是代理模式的一個非常經典的應用。
MapperProxy如何實現對接口的代理?
JDK動態代理
我們知道,JDK動態代理有三個核心角色:
被代理類(即就是實現類)接口實現了InvocationHanndler的觸發管理類,用來生成代理對象。被代理類必須實現接口,因為要通過接口獲取方法,而且代理類也要實現這個接口。
而Mybatis中並沒有Mapper接口的實現類,怎麼被代理呢?它忽略了實現類,直接對Mapper接口進行代理。
MyBatis動態代理:
在Mybatis中,JDK動態代理為什麼不需要實現類呢?
這裡我們的目的其實就是根據一個可以執行的方法,直接找到Mapper.xml中statement ID ,方便調用。
最後返回的userMapper就是MapperProxyFactory的創建的代理對象,然後這個對象中包含了MapperProxy對象,
問題3:到底是怎麼根據Mapper.java找到Mapper.xml的?
最後我們調用userMapper.selectUserById(),本質上調用的是MapperProxy的invoke()方法。
請看下面這張圖:
如果根據(接口+方法名找到Statement ID ),這個邏輯在InvocationHandler子類(MapperProxy類)中就可以完成了,其實也就沒有必要在用實現類了。
總結
本文中主要是講getMapper方法,該方法實質上是獲取一個JDK動態代理對象(類型是Proxy+數字),這個代理類會繼承MapperProxy類,實現被代理的接口UserMapper,並且裡面持有一個MapperProxy類型的觸發管理類。這裡我們就拿到代理類了,後面我們就可以使用這個代理對象進行方法調用。
問題涉及到的設計模式:
代理模式。工廠模式。單例模式。整個流程圖:
冰凍三尺,非一日之寒表面意義是冰凍了三尺,並不是一天的寒冷所能達到的效果。學習亦如此,你每一天的一點點努力,都是為你以後的成功做鋪墊。