1. 程式人生 > >深度 Mybatis 3 原始碼分析(一)SqlSessionFactoryBuilder原始碼分析

深度 Mybatis 3 原始碼分析(一)SqlSessionFactoryBuilder原始碼分析

MyBatis消除了幾乎所有的JDBC程式碼和引數的手工設定以及對結果集的檢索封裝。MyBatis可以使用簡單的XML或註解用於配置和原始對映,將介面和Java的POJO(Plain Old Java Objects,普通的Java物件)對映成資料庫中的記錄。

Mybatis環境快速入門

Maven依賴資訊

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>sourceanalysis</artifactId>
        <groupId>com.brian</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>


    <artifactId>mybatis3</artifactId>
    <groupId>com.brian</groupId>
    <version>0.0.1-SNAPSHOT</version>
    <description>原始碼分析 - mybatis3原始碼分析</description>


    <dependencies>
        <!--mysql資料庫驅動 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>

        <!-- mybatis ORM框架 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.1</version>
        </dependency>
    </dependencies>

</project>

建立mybatis配置檔案 mybatis.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 環境配置 -->
    <environments default="dev">
        <environment id="dev">
            <transactionManager type="JDBC"/>
            <!-- 資料庫連線相關配置 ,這裡動態獲取config.properties檔案中的內容-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:14110/brian?useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!-- mapping檔案路徑配置 -->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>

</configuration>

Mapper配置檔案

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mapper.UserMapper">
    <select id="getUser" parameterType="int"
            resultType="entity.User">
        select * from user where id=#{id}
    </select>
</mapper>

執行MyBatis程式碼

import mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.Reader;

/**
 * @program: architect
 * @author: Brian Huang
 * @create: 2019-06-04 22
 **/
public class MybatisApp {

    public static void main(String[] args) {
        try {
            //1.定義配置檔案
            String resource = "mybatis.xml";
            //2.獲取InputStreamReader IO流
            Reader reader = Resources.getResourceAsReader(resource);
            //3.獲取SqlSessionFactory
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            //4.獲取Session
            SqlSession session = sqlSessionFactory.openSession();
            //5.執行mapper介面方法
            UserMapper mapper = session.getMapper(UserMapper.class);
            System.out.println("--result--: " + mapper.getUser(1).toString());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

資料表結構

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '使用者名稱',
  `password` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密碼,加密儲存',
  `phone` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '註冊手機號',
  `email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '註冊郵箱',
  `created` datetime(0) NOT NULL,
  `updated` datetime(0) NOT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `username`(`username`) USING BTREE,
  UNIQUE INDEX `phone`(`phone`) USING BTREE,
  UNIQUE INDEX `email`(`email`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 36 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '使用者表' ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

Mybatis大體架構流程分析

1. 讀取resources獲取對應的Reader物件。

Reader reader = Resources.getResourceAsReader(resources);

2. 使用SqlSessionFactoryBuilder獲取SqlSessionFactory

SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);

原始碼分析:

2.1.進入到build 傳遞reader有引數建構函式

最終執行

2.2. SqlSessionFactoryBuilder使用XMLConfigBuilder解析配置檔案,封裝成Configuration物件。

 

注意:parsed = false,避免maybatis.xml被載入多次,因為我們的configuration是全域性的所以只能被解析一次

 2.3 執行environmentsElement()  方法

 

此處for迴圈是environment可能回配置多個執行環境如dev,test,prod等

 2.4 執行mapperElement()方法 解析mybatis.xml裡面的<mappers>節點

 

這裡的Mapper有兩種掃描的方式 package和resource,根據我上面的mybatis.xml配置檔案,這裡會走第一個判斷

2.5 執行XMLMapperBuilder的parse()方法,解析UserMapper.xml

2.5.1 isResourceLoaded() 判斷避免mapper被重複解析

 

2.5.2 configurationElement()執行具體的解析UserMapper.xml邏輯

2.5.3 addLoadedResource()方法Mapper路徑放入到loadedResoures中

 

 2.5.4 執行bingMapperForNamesapce() 將UserMapper.XML和UserMapper.java 進行對映

 

總環下流程圖 (PS 圖畫的不是太好看) 紅色框為SqlSessionFactoryBuilder的執行邏輯

&n