摘要:在找那個可以根據(jù)中的屬性,確定類的全限定類名。并且根據(jù)節(jié)點所對應(yīng)的,找到所要執(zhí)行的方法。因為他根據(jù)的是類名方法名進行唯一確定節(jié)點的。
當(dāng)我們使用sqlSession.getMapper(xx.class)方法時,Mybatis其實是使用了jdk的動態(tài)代理技術(shù),在MapperProxyFactory中生成對應(yīng)的Mapper對象。
這段是MappedProxyFactory中的一段代碼
protected T newInstance(MapperProxymapperProxy) { return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy); }
其中mapperProxy對應(yīng)的是MapperProxy,該類實現(xiàn)了InvocationHanlder接口。
正如我們所知,JDK的動態(tài)代理是根據(jù)接口來生成代理對象的。在Mybatis找那個可以根據(jù)Mapper.xml中的namespace屬性,確定類的全限定類名。并且根據(jù)節(jié)點(insert | select | update | delete)所對應(yīng)的ID,找到所要執(zhí)行的方法。也因此,Mybatis中的方法是不能重載的。因為他根據(jù)的是類名+方法名進行唯一確定MapperStatement(節(jié)點)的。
這個就是MapperStatement所封裝的一些信息了
再接著,當(dāng)我們調(diào)用Mapper對應(yīng)的方法時,此時,會交給代理對象進行處理。
MapperProxy#的invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(Object.class.equals(method.getDeclaringClass())) { try { return method.invoke(this, args); } catch (Throwable var5) { throw ExceptionUtil.unwrapThrowable(var5); } } else { //執(zhí)行到這一步,如果方法是第一次調(diào)用,那么會創(chuàng)建對象,如果不是則使用緩存 //需要注意的是調(diào)用的cacheMapperMethod方法,其實就是用一個Map進行緩存 MapperMethod mapperMethod = this.cachedMapperMethod(method); return mapperMethod.execute(this.sqlSession, args); } }
緊接著,調(diào)用了MapperMethod#execute(this,sqlSession,args);
這個方法比較簡單,就是根據(jù)節(jié)點的類型,進行相應(yīng)的處理。比如節(jié)點是insert 那就走到insert的邏輯,其他類似了。。。
本人的節(jié)點類型是select,方法返回值是list,所以代碼執(zhí)行了這個方法
privateObject executeForMany(SqlSession sqlSession, Object[] args) { Object param = this.method.convertArgsToSqlCommandParam(args); List result; if(this.method.hasRowBounds()) { RowBounds rowBounds = this.method.extractRowBounds(args); result = sqlSession.selectList(this.command.getName(), param, rowBounds); } else { result = sqlSession.selectList(this.command.getName(), param); } return !this.method.getReturnType().isAssignableFrom(result.getClass())?(this.method.getReturnType().isArray()?this.convertToArray(result):this.convertToDeclaredCollection(sqlSession.getConfiguration(), result)):result; }
這里看到方法還執(zhí)行了convertArgsToSqlCommandParam(args)方法,這個方法返回的對象值如下。其實說白了,就是對我們傳進去參數(shù)的封裝。需要注意到,這邊其實是個Map對象,因為我的Mapper接口的方法是使用@Param注解的形式的。如果你傳進去的是個POJO或者Map,那么這邊就是POJO或者Map,如果是基本數(shù)據(jù)類型(單個值),那么會被轉(zhuǎn)換成包裝數(shù)據(jù)類型
中間的有些步驟就省略了。接下里的話,會將于需要執(zhí)行的對象的方法,sql,sql參數(shù)創(chuàng)建一個緩存key
.
然后調(diào)用CacheExecutor#query,根據(jù)key查詢有沒有緩存,如果有緩存,直接從緩存中拿,如果沒有,則繼續(xù)執(zhí)行。
期間會調(diào)用一個比較重要的方法 BaseExecutor#queryFromDatabase
privateList queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER); //key其實就是之前提到過的CacheKey,value只是充當(dāng)一個占位。。 List list; try { list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql); //代碼執(zhí)行到這里。。。 } finally { this.localCache.removeObject(key); } this.localCache.putObject(key, list); if(ms.getStatementType() == StatementType.CALLABLE) { this.localOutputParameterCache.putObject(key, parameter); } return list; }
下面就是比較關(guān)鍵的地方了
代碼執(zhí)行了simpleExecutor#doQuery
publicList doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; List var9; try { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql); stmt = this.prepareStatement(handler, ms.getStatementLog()); var9 = handler.query(stmt, resultHandler); } finally { this.closeStatement(stmt); } return var9; }
從這邊可以看出在Executor內(nèi)創(chuàng)建了StatementHandler,并對參數(shù)進行了預(yù)處理,而調(diào)用的handler.query()方法后,var9的值,就是我們所要查詢的結(jié)果了。
值得一提的是StatementHandler有4個默認(rèn)的實現(xiàn)類:
RoutingStatementHandler:這是一個封裝類,不提供具體的實現(xiàn),根據(jù)Executor的類型,創(chuàng)建不同的類型的StatementHandler
SimpleStatementHandler:這個類對應(yīng)于JDBC的Statement對象,用于沒有預(yù)編譯參數(shù)的SQL的運行
PreparedStatementHandler:用于預(yù)編譯參數(shù)SQL的運行
CallableStatementHandler:用于存儲過程的調(diào)度
在newStatementHandler方法中,我們也可以看到是創(chuàng)建了RoutingStatementHandler對象,會根據(jù)具體的Executor類型,創(chuàng)建不同的StatementHandler。而這個具體的StatementHandler被存儲在了RoutingStatementHandler的delegate屬性中
先看configuration#newStatementHandler。注意到這邊有個interceptorChain.pluginAll 這邊就是用來執(zhí)行插件的。
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); StatementHandler statementHandler = (StatementHandler)this.interceptorChain.pluginAll(statementHandler); return statementHandler; }
這個是所創(chuàng)建的StatementHandler所包含的信息,可以看到包含了很多東西
再來看simpleExecutor#prepareStatement
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Connection connection = this.getConnection(statementLog); // 在此處獲取了數(shù)據(jù)的連接,此對象是個包裝對象,包裝了JDBC的Connection Statement stmt = handler.prepare(connection); // 這邊是進行一些預(yù)處理 handler.parameterize(stmt); return stmt; }
這邊的調(diào)用的parameterize的方法就是對參數(shù)進行預(yù)處理了。其實就是遍歷parameterMappings集合,然后從里面取出參數(shù)的屬性,對參數(shù)進行處理,這個就是這個方法的邏輯。(注:parameterMappings 集合中存放的是傳遞進來的參數(shù)的屬性)
當(dāng)查詢到結(jié)果到時候,會調(diào)用DefaultResultSetHandler對結(jié)果進行包裝。并且查詢完結(jié)果后,會將結(jié)果放到緩存中去
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/67751.html
摘要:的解析和運行原理構(gòu)建過程提供創(chuàng)建的核心接口。在構(gòu)造器初始化時會根據(jù)和的方法解析為命令。數(shù)據(jù)庫會話器定義了一個對象的適配器,它是一個接口對象,構(gòu)造器根據(jù)配置來適配對應(yīng)的對象。它的作用是給實現(xiàn)類對象的使用提供一個統(tǒng)一簡易的使用適配器。 MyBatis的解析和運行原理 構(gòu)建SqlSessionFactory過程 SqlSessionFactory提供創(chuàng)建MyBatis的核心接口SqlSess...
摘要:避免了幾乎所有的代碼和手動設(shè)置參數(shù)以及獲取結(jié)果集。這個對象主要是獲取方法對應(yīng)的命令和執(zhí)行相應(yīng)操作等的處理,具體細(xì)節(jié)同學(xué)們可以抽空研究。所以這里的方法主要使用了和對象幫助我們處理語句集和參數(shù)的處理。 博文目標(biāo):希望大家看了這篇博文后,對Mybatis整體運行過程有一個清晰的認(rèn)識和把握。 1.什么是 MyBatis ? MyBatis 是一款優(yōu)秀的持久層框架,它支持定制化 SQL、存儲過程...
摘要:一級緩存介紹及相關(guān)配置。在這個章節(jié),我們學(xué)習(xí)如何使用的一級緩存。一級緩存實驗配置完畢后,通過實驗的方式了解一級緩存的效果。源碼分析了解具體的工作流程后,我們隊查詢相關(guān)的核心類和一級緩存的源碼進行走讀。 我,后端Java工程師,現(xiàn)在美團點評工作。愛健身,愛技術(shù),也喜歡寫點文字。個人網(wǎng)站: http://kailuncen.me公眾號: KailunTalk (凱倫說) 前言 本文主要涉及...
摘要:一級緩存介紹及相關(guān)配置。在這個章節(jié),我們學(xué)習(xí)如何使用的一級緩存。一級緩存實驗配置完畢后,通過實驗的方式了解一級緩存的效果。源碼分析了解具體的工作流程后,我們隊查詢相關(guān)的核心類和一級緩存的源碼進行走讀。 我,后端Java工程師,現(xiàn)在美團點評工作。愛健身,愛技術(shù),也喜歡寫點文字。個人網(wǎng)站: http://kailuncen.me公眾號: KailunTalk (凱倫說) 前言 本文主要涉及...
閱讀 6912·2021-09-22 15:08
閱讀 1920·2021-08-24 10:03
閱讀 2437·2021-08-20 09:36
閱讀 1315·2020-12-03 17:22
閱讀 2474·2019-08-30 15:55
閱讀 905·2019-08-29 16:13
閱讀 3053·2019-08-29 12:41
閱讀 3249·2019-08-26 12:12