MyBatis架構
MyBatis依賴的jar不多,而且代碼行數也沒多少,其中使用了大量的設計模式,值得好好學習。下圖是MyBatis的一張架構圖,來自Java框架篇—Mybatis 入門。
Mybatis的功能架構分為三層:
- API接口層:提供給外部使用的接口API,開發人員通過這些本地API來操縱數據庫。接口層一接收到調用請求就會調用數據處理層來完成具體的數據處理。
- 數據處理層:負責具體的SQL查找、SQL解析、SQL執行和執行結果映射處理等。它主要的目的是根據調用的請求完成一次數據庫操作。
- 基礎支撐層:負責最基礎的功能支撐,包括連接管理、事務管理、配置加載和緩存處理,這些都是共用的東西,將他們抽取出來作為最基礎的組件。為上層的數據處理層提供最基礎的支撐。
MyBatis整個項目的包結構如下:
.
└── org
└── apache
└── ibatis
├── annotations
├── binding
├── builder
├── cache
├── cursor
├── datasource
├── exceptions
├── executor
├── io
├── jdbc
├── logging
├── mapping
├── parsing
├── plugin
├── reflection
├── scripting
├── session
├── transaction
└── type
1.兵馬未動,日志先行
org.apache.ibatis.logging
org.apache.ibatis.logging.commons
org.apache.ibatis.logging.jdbc
org.apache.ibatis.logging.jdk14
org.apache.ibatis.logging.log4j
org.apache.ibatis.logging.log4j2
org.apache.ibatis.logging.nologging
org.apache.ibatis.logging.slf4j
org.apache.ibatis.logging.stdout
2.異常
org.apache.ibatis.exceptions
3.緩存
org.apache.ibatis.cache
org.apache.ibatis.cache.decorators
org.apache.ibatis.cache.impl
4.解析
org.apache.ibatis.parsing
xml解析,${} 格式的字符串解析
源碼分析可以參考http://www.cnblogs.com/sunzhenchao/p/3161093.html
5.類型處理器
org.apache.ibatis.type
實現java和jdbc中的類型之間轉換
源碼分析可以參考http://www.cnblogs.com/sunzhenchao/archive/2013/04/09/3009431.html
6.IO
org.apache.ibatis.io
通過類加載器在jar包中尋找一個package下滿足條件(比如某個接口的子類)的所有類
7.反射
org.apache.ibatis.reflection
org.apache.ibatis.reflection.factory
org.apache.ibatis.reflection.invoker
org.apache.ibatis.reflection.property
org.apache.ibatis.reflection.wrapper
可以參考MetaObjectTest來跟蹤調試,基本上用到了reflection包下所有的類
8.數據源
org.apache.ibatis.datasource
org.apache.ibatis.datasource.jndi
org.apache.ibatis.datasource.pooled
org.apache.ibatis.datasource.unpooled
9.事務
org.apache.ibatis.transaction
org.apache.ibatis.transaction.jdbc
org.apache.ibatis.transaction.managed
10.會話
org.apache.ibatis.session
org.apache.ibatis.session.defaults
11.jdbc單元測試工具
org.apache.ibatis.jdbc
12.構建
org.apache.ibatis.builder
org.apache.ibatis.builder.annotation
org.apache.ibatis.builder.xml
13.映射
org.apache.ibatis.mapping
14.腳本
org.apache.ibatis.scripting
org.apache.ibatis.scripting.defaults
org.apache.ibatis.scripting.xmltags
15.注解
org.apache.ibatis.annotations
16.綁定
org.apache.ibatis.binding
17.執行器
org.apache.ibatis.executor
org.apache.ibatis.executor.keygen
org.apache.ibatis.executor.loaderorg.apache.ibatis.executor.loader.cglib
org.apache.ibatis.executor.loader.javassist
org.apache.ibatis.executor.parameter
org.apache.ibatis.executor.result
org.apache.ibatis.executor.resultset
org.apache.ibatis.executor.statement
18.插件
org.apache.ibatis.plugin
注釋①
mybatis通過SqlSessionFactoryBuilder作為入口,通過傳入配置文件,使用了BaseBuilder實現類進行配置文件解析,具體實現類是XMLConfigBuilder,在這里mybatis對配置的項進行了全面解析,只不過不是所有的解析都放在了XMLConfigBuilder,XMLConfigBuilder解析了二級節點,並作為一個總入口,還有另外幾個類繼承了BaseBuilder,用於解析不同的配置。而解析到的配置項信息,基本都保存在了Configuration這個類,可以看到多處地方依賴到它。
之后通過配置獲取到SqlSessionFactory,可以看到SqlSessionFactoryBuilder提供了一個build方法,就是返回SqlSessionFactory的。
注釋②
而SqlSessionFactory只是一個接口,默認實現有DeaultSqlSessionFactory。通過SqlSessionFactory.openSession的幾個多態方法,可以獲取到SqlSession。
注釋③
而SqlSession也只是一個接口,怎么理解SqlSession呢,其實Session即是一次會話,假如我們把某次請求與數據庫連接Connection的交互,看成是一次會話,那就可以理解SqlSession了。SqlSession是請求與數據庫的一次交互,交互完成之后,Session則結束,但Session結束不代表數據庫連接也關閉,只是這次會話終止了,但是數據庫連接依舊是返回給連接池。
這里的SqlSession即是對一次交互信息的封裝,請求可以通過SqlSession的方法(如圖:CRUD )進行操作,而數據庫連接,依舊由SqlSessionFactory注入。
注釋②
如圖我們可以看到SqlSessionFactory獲取到TransactionFactory,一個事務的工廠類接口,而通過這個工廠具體實現類可以產生多個事務Transaction(具體參考ManagedTransactionFactory),Transaction抽象了一個方法getConnection,通過這個方法我們可以獲取到不同事務級別的connection。mybatis的代碼是這樣的:
ManagedTransaction.java
protected void openConnection() throws SQLException {
if (log.isDebugEnabled()) {
log.debug(“Opening JDBC Connection”);
}
this.connection = this.dataSource.getConnection();
if (this.level != null) {
this.connection.setTransactionIsolation(this.level.getLevel());
}
}
注釋④
這個時候可能大家覺得萬事俱備了,SqlSession都定義好了CRUD 方法了,那它也會幫忙將語句扔給Connection操作,其實不然。這里mybatis還抽象了接口Execute。
Execute才是真正將sql與Connection打交道的地方。
圖中我們可以看到Execute有四個實現類,通過名稱我們不難發現它們各自的用途,例如CachingExecutor.java,mybatis默認是有緩存的,就是通過這個類實現的。
還有一個點,每個Execute實現類中,都可以發現有這樣一個定義和構造方法
private Executor delegate;
public CachingExecutor(Executor delegate) {
this.delegate = delegate;
delegate.setExecutorWrapper(this);
}
所以這里我們也可以看到,其實Executor有個鏈結構,一步一步往下執行,所以在真正執行查詢時,外面是嵌套了一層CachingExecutor,證據在這里。
- public Executor newExecutor(Transaction transaction, ExecutorType executorType, boolean autoCommit) {
- executorType = executorType == null ? defaultExecutorType : executorType;
- executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
- Executor executor;
- if (ExecutorType.BATCH == executorType) {
- executor = new BatchExecutor(this, transaction);
- } else if (ExecutorType.REUSE == executorType) {
- executor = new ReuseExecutor(this, transaction);
- } else {
- executor = new SimpleExecutor(this, transaction);
- }
- if (cacheEnabled) {
- executor = new CachingExecutor(executor, autoCommit);
- }
- executor = (Executor) interceptorChain.pluginAll(executor);
- return executor;
- }
在Execute中,還有更深層的執行邏輯,這個后面文章繼續分析。
轉載請注明出處:http://sukerz.scse.cn/index.php/2016/02/01/mybatis-framework/