從上圖可能看出,在?mybatis 中, SqlSession 的實現(xiàn)類有兩個,其中 SqlSessionManager 類不但實現(xiàn)了 SqlSession 接口,同時也實現(xiàn)了 SqlSessionFactory 接口。那么 SqlSessionManager 類究竟有何作用? ?? 由于源碼中缺少注釋,所以從 mybatis 目前的提供官方文檔來看,似乎該類已被棄用,其功能被 DefaultSqlSession 類和 DefaultSqlSessionFactory 類所代替。只是該類的部分代碼對我們理解 mybatis 的一些底層機制還具有一定的參考價值,例如:
SqlSessionManager的下面的構(gòu)造方法,會產(chǎn)生一個SqlSession 的一個代理對象:
?
private
SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
this
.sqlSessionFactory =
sqlSessionFactory;
this
.sqlSessionProxy =
(SqlSession) Proxy.newProxyInstance(
SqlSessionFactory.
class
.getClassLoader(),
new
Class[]{SqlSession.
class
},
new
SqlSessionInterceptor());
}
?
SqlSessionInterceptor類實現(xiàn)了InvocationHandler接口
privaprivate
class
SqlSessionInterceptor
implements
InvocationHandler {
public
Object invoke(Object proxy, Method method, Object[] args)
throws
Throwable
{
final
SqlSession sqlSession = SqlSessionManager.
this
.localSqlSession.get();
if
(sqlSession !=
null
) {
try
{
return
method.invoke(sqlSession, args);
}
catch
(Throwable t) {
throw
ExceptionUtil.unwrapThrowable(t);
}
}
else
{
final
SqlSession autoSqlSession =
openSession();
try
{
final
Object result =
method.invoke(autoSqlSession, args);
autoSqlSession.commit();
return
result;
}
catch
(Throwable t) {
autoSqlSession.rollback();
throw
ExceptionUtil.unwrapThrowable(t);
}
finally
{
autoSqlSession.close();
}
}
}
}
private
class
SqlSessionInterceptor
implements
InvocationHandler {
public
Object invoke(Object proxy, Method method, Object[] args)
throws
Throwable
{
final
SqlSession sqlSession = SqlSessionManager.
this
.localSqlSession.get();
if
(sqlSession !=
null
) {
try
{
return
method.invoke(sqlSession, args);
}
catch
(Throwable t) {
throw
ExceptionUtil.unwrapThrowable(t);
}
}
else
{
final
SqlSession autoSqlSession =
openSession();
try
{
final
Object result =
method.invoke(autoSqlSession, args);
autoSqlSession.commit();
return
result;
}
catch
(Throwable t) {
autoSqlSession.rollback();
throw
ExceptionUtil.unwrapThrowable(t);
}
finally
{
autoSqlSession.close();
}
}
}
}
下面對這一段使用JAVA 動態(tài) 代理技術(shù)產(chǎn)生SqlSession 代理對象的代碼進行分析:
this.sqlSessionProxy?=?(SqlSession)?Proxy.newProxyInstance(
????????SqlSessionFactory.class.getClassLoader(),
????????new?Class[]{SqlSession.class},
????????new?SqlSessionInterceptor())??這句是關(guān)鍵, JDK 的 Proxy 類的 newProxyInstance 方法的方法原型如下:
public?static?Object?newProxyInstance(ClassLoader?loader,
??Class<?>[]?interfaces,
??InvocationHandler?h)
throws?IllegalArgumentException
在調(diào)這個方法中需要傳入三個參數(shù):
??一個 interfaces 的數(shù)組參數(shù)
??一個 InvocationHanler? 接口的實例對象
??一個類加載器,
則Proxy.newProxyInstance方法執(zhí)行后會返回 interfaces 中任一接口的實例對象(假設(shè)該對象為 proxyObject), 那么當(dāng)我們在調(diào)用這個對象 proxyObject 的相應(yīng)方法時,就會進入到 InvocationHandler? 這個參數(shù)對象的 invoke(Object?proxy,?Method?method,?Object[]?args)方法中,或者換句話說,就會被h 這個對象的 invoke 方法攔截 ,? 對象 proxyObject 會作為
Invoke 中的 proxy 參數(shù), proxyObject 調(diào)用的方法的方法對象會作為 method 參數(shù) , 方法的參數(shù)會作為 args 參數(shù) ,這樣在 InvocationHandler? 對象的 invoke 方法中,就會通過 Method.invoke 方法來執(zhí)行具體的目標(biāo)對象的相應(yīng)方法,在 mybatis 的這個應(yīng)用場景上,這個目標(biāo)對象其實就是一個 SqlSession 的實例 , 通過 SqlSessionManager 類的成員變量 sqlSessionFactory的openSession()獲得或者從當(dāng)前線程中獲取。
?
以上的實現(xiàn)技術(shù)主要就是使用了 java 的動態(tài)代理技術(shù),看到網(wǎng)上不少人在問這個 InvocationHandler? 接口中的 invoke 方法的第一個參數(shù) proxy 究竟有何作用,這個 proxy 其實就是一個代理對象實例(通過 Proxy.newProxyInstance方法產(chǎn)生),下面就舉例說明一下它的作用:
可參照?java.rmi.server.RemoteObjectInvocationHandler類中的相應(yīng)方法invoke 方法,一個用法就是判斷 invoke 的 method 參數(shù),看是否有必要調(diào)用 proxy 對象的其他方法,另一個用處就是作為參數(shù)把該對象提供給遠程調(diào)用的方法使用。 ?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

