簡介:spring
MyBatis 是一款優秀的持久層框架,它支持定製化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎全部的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 可使用簡單的 XML 或註解來配置和映射原生信息,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對象)映射成數據庫中的記錄。sql
摘自官網。。數據庫
爲何要使用mybatis,相信看這篇文章的童鞋都有所瞭解,俺這裏就多廢話幾句。在orm框架中,有輕量級的dbutils與mybatis,重量級的有hibernate。緩存
爲何要選擇mybatis呢?緣由以下:session
1.簡單,這個無需我多廢話。確定的啊,使用過的童鞋都知道,在dao層定義一個接口,而後定義一個對應的xml(xml中namespace的值對應接口的全限定名就ok。由於mybatis是經過namespaceid去和接口類進行映射,而後使用動態代理建立接口類的實例方法,參見動態代理). mybatis
2.結果集映射,我認爲這是mybatis作的最牛的一點,也是選擇他最大的一個理由架構
3.完善的緩存機制(mybatis有1級緩存和2級緩存),1級緩存是基於會話的(Session),2級緩存是基於應用級別。這裏不作過多闡述,有興趣的能夠參考文章 http://www.iteye.com/topic/1112327/框架
4.強大的插件機制。它能夠在運行過程當中動態的執行你本身的業務邏輯,好比防止sql注入,分頁,sql日誌打印,sql執行耗時等均可以在插件中作。真正實現了業務與功能分離。讓你隨行所欲的在飛dao層中增長任何你想作的事情。ide
好了。上面說了那麼多好處,本文中會有點穿插,但重點是插件機制。廢話很少說,咱們開始縷一縷mybatis的流程ui
固然,最古老的方式就不去講了(就是去調用mybatis select, selectOne這種方式),咱們直接從接口的玩法中入手
這是mybatis的一張架構圖,從中咱們能夠看得出。應用程序去調用對應的db操做時會經歷 配置->打開會話->在會話中執行相應的操做,同時會話中包含了jdbc的事務(對,沒錯。就是jdbc的事務)。那麼咱們能夠看得出來,會話是核心。而配置是關鍵。
咱們能夠打開配置類看看,中間有不少屬性。咱們絕大多數均可以忽略,可是
這個就是mybatis內部維護的攔截器鏈。咱們在解析配置,初始化的時候會給xml中寫入一個攔截器的類,他是從
Configuration.addInterceptor(Interceptor interceptor)
這個方法中寫入。這一點對於本文來說很重要,請你們牢記。
接下來講會話。有心急的小夥伴就會提問,插件和會話有關係嗎?
必然的事情,要否則我也不會羅裏吧嗦的說這麼多關於會話的東西。咱們能夠看看sqlsession的結構
能夠看得出來,他有2個實現類(用過spring的童鞋應該知道,sqlsessionTemplate是spring對sqlsession的簡單封裝,這裏再也不贅述), 那麼就剩下了DefaultSqlSession和SqlSessionManager這兩個類。
那麼咱們能夠作一個大膽的假設,mybatis他默認打開的是DefaultSqlSession(其實在源碼中是的)。咱們要構建一個sqlsession的時候會使用 SqlSessionFactoryBuilder 這個類,經過傳遞一個抽象的Reader對象(是否是很眼熟?這玩意就是IO流裏的字節流基類), 經過這個玩意傳一個xml文件進來
而後去構建一個SqlSessionFactory對象。
能夠看得出,它是new的defaultSqlSessionFactory這個類。咱們跟進去看看
這裏沒什麼稀奇的,無非就是把咱們文件中的那些屬性轉移給這個Configuration類中,至於這個類裏面具體有什麼我就不帶你們看了。咱們繼續看打開會話的流程
到這裏他的會話構建就出來了,有心的童鞋這裏應該能看到了吧,我上面說的jdbc事務和DefaultSqlSession
ok,咱們打開這個類看看,裏面全是一些模板方法。俺這裏就不一一贅述
咱們的重點是從
執行器(我暫且叫他執行器,也比較形象)開始
他這裏就有好多個實現類了。老規矩。我就不帶着你們找了,直接上圖。默認的執行器類型是SimpleExecutor
找到這裏,咱們就會發現,這就是它的增刪改查了。老規矩,不贅述
繼續深刻,接下來是插件部分的重點了:
在開始以前咱們須要介紹一下,它的攔截器能夠做用於
這些範圍。
我在上面說過,interceptorChain 這個東東很重要,這就是咱們的攔截器鏈。咱們能夠看到他會使用pluginAll(Object target)這個方法將全部攔截器加到攔截器鏈中。
而攔截器類是這樣的。
若是咱們須要實現一個本身的攔截器則須要實現這個接口中的方法。
其中
Object intercept(Invocation invocation) throws Throwable; // 這個方法是攔截器的業務方法
Object plugin(Object target); // 這個方法是對攔截器的包裝, 若是不包裝的話它是不會被加入到攔截器鏈中
void setProperties(Properties properties);// 這個方法是設置一些額外的屬性
看明白這個以後咱們本身手動去編寫一個攔截器類
/** * @author Autorun * Created by Autorun on 2018/1/4. */ @Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class}) }) public class LogInterceptor implements Interceptor { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Override public Object intercept(Invocation invocation) throws Throwable { return invocation.proceed(); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { } }
@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class}) })
這一行是標註要攔截哪一個類上的方法,參數等。而後使用動態代理的invoke(Object obj, Object... args)方法,執行咱們的邏輯
若是有多個攔截器則按照順序(由於他內部是使用的ArrayList容器,有序可重複,你們都懂得)
具體執行的話是使用Plugin類中的Object invoke(Object proxy, Method method, Object[] args) throws Throwable 方法來作的。能夠看得出來。它裏面調用了咱們編寫的 Object intercept(Invocation invocation) throws Throwable;
以後咱們須要把咱們寫的攔截器類注入到攔截器鏈中。
在mybatis的配置文件中加入
<!-- mybatis-config.xml --> <plugins> <!-- 類的全限定名 --> <plugin interceptor="org.mybatis.example.ExamplePlugin"> </plugin> </plugins>
使咱們的攔截器生效。運行程序就會發現咱們的業務在對應的範圍生效了。
文章編寫的比較倉促,若是有問題能夠留言給我,我會一一回復你們。謝謝