Mybatis源碼淺析、定製原理及方法

mybatis爲javaer們提供了強大的數據庫訪問支持,但對於絕大多數場景來說,使用上仍然不夠簡單,比如:還是需要編寫包含sql語句的xml或註解。本文對mybatis的原理進行了簡單的介紹,並介紹了我們部門自己基於mybatis源代碼修改並開發的mybatis擴展框架appassist-dao.

1.Mybatis基礎

1.兩種Mybatis使用方式

  1. spring集成方式
  2. 直接調用初始化方式
    • 下圖時兩種初始化方式之間的關係
      這裏寫圖片描述
      圖1

2.Mybatis-spring的初始化流程

  • mybatis-spring是對mybatis的封裝,因此實際上mybatis-spring的初始化流程包含了標準的mybais初始化流程。下圖展示了mybatis-spring初始化的大體流程,其中紅框部分會進行mapper xml的掃描,也就是右側的流程部分。
    這裏寫圖片描述

    圖2

  • mybatis-spring除了可以使用SqlSessionFacotryBean來初始化各個mapper,還可以用MapperScanConfigurer來掃描指定包路徑下的Mapper接口,自動向spring框架中注入對應的Mapper實現:
    這裏寫圖片描述

    圖3

4. Mybatis兩種使用模式—— 傳統模式SqlSession和MapperProxy:

圖4,圖5來源:https://github.com/nero520/mybatis

傳統模式,使用SqlSession進行訪問:
這裏寫圖片描述

圖4

MapperProxy模式:
這裏寫圖片描述
圖5

3. MapperProxy做了些什麼?

MapperProxy實際上是一個JDK代理:InvocationHandler。被代理的,則是與xxxMapper.xml中namespace對應的接口。
這裏寫圖片描述

圖6

4.Mybatis定製——實現基礎Dao類:BaseDao,併爲繼承BaseDao類的Mapper接口自動注入mybatis sql xml。

1)需要定製的功能:

比如,目前在我們部門內測時候用的dao框架 appassist-dao,它定義了一個基礎接口,凡是集成自該接口的Dao對象,都會根據它的類型參數”T extends BaseQuery”去生成對應的sql語句。

public interface BaseDao<T extends BaseQuery, KEY extends Serializable> {
    int insert(T instance);
    int insertAll(Collection<T> instances);
    int insertAllBatch(Collection<T> instances);
    int deleteByKeys(KEY... keys);
    int deleteByCondition(T condition);
    List<T> selectListByCondition(T condition);
    T selectOneByKey(KEY key);
    T selectOneByCondition(T condition, boolean strictlyCheck) throws SelectOneException;
    int selectCount(T condition);
    List<T> selectListByKeys(KEY... keys);
    int updateByKey(T instance);
    int updateByCondition(@Param("update") T update, @Param("condition") T condition);
}

舉個例子:
我們定義一個Dao,並定義對應的Domain對象(即PO對象)。

public interface UserDao extends BaseDao<User, Long> {
}
@Table("sys_user")
public class User extends BaseQuery {
    @Column(primaryKey = true)
    private Long id;

    @Column
    private String name;

    @Column("age")
    private Integer age;

    @Column("health_condition")
    private String healthCondition;
}

appassist-dao可以使得數據庫訪問變得更簡單,就如上述兩個類:User和UserDao。只要將UserDao掃描並實例化注入到spring中,就能夠像如下使用:

@Resource
private UserDao userDao;
@Override
public void testUserDao() {
    User user1 = new User();
    user1.setName("haha");
    User user2 = new User();
    user2.setName("hehe");

    // 將name爲"haha"和"hehe"的兩個User插入sys_user表中。
    int insertCount = userDao.insertAll(Arrays.asList(user1, user2)); 
}

2)定製功能的實現

前面有講到,spring中,Mybatis的初始化入口爲:SqlSessionFactoryBean。爲了在mybatis初始化的時候能夠掃描UserDao和User類,並根據User類中的註解自動生成sql註冊到Mybatis中。我們需要對它進行改寫。
一共有兩個hack點:
1. 圖2中的綠色部分
這裏寫圖片描述
對應mybatis源碼:

MybatisXMLMapperBuilder.parse();

這裏寫圖片描述

  1. MapperScannerConfigurer將對象自動掃描注入後,對Dao接口方法進行註解掃描
    對應mybatis源碼:
MybatisMapperAnnotationBuilder.parse();

這裏寫圖片描述

其中紅框部分即爲我們自己添加的Sql自動生成並註冊mybatis的代碼。
AutoSqlInjector中,根據Domain對象中Table、Column註解等信息,生成對應的BaseDao中方法所對應的mybatis sql片段。再通過調用

builderAssistant.addMappedStatement

方法,來將生成好sql片段註冊到mybatis中。

3)這樣定製帶來的幾大好處

  1. mybatis orm化,對於大多數應用場景無需mapper xml文件,即可使用。
  2. 採用了比較好的Mybatis實踐來實現方法,由sql技術大牛統一編寫mybatis sql,避免大多數情況下自己編寫sql導致的問題。
  3. 能夠植入一些mybatis不具備的特別的功能,比如dao方法監控自動接入、分庫分表、過濾空條件update和delete。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章