手写MyBatis,纯手工打造开源框架(第二篇:君临天下)_mybatis

说明

MyBatis版本:3.5.1

 

 

 

前言

       通过上面一篇我们理了一下整个编码的思路,这一篇,我们主要是解决配置文件解析和一些基本配置的工作。

一、准备工作

1.1 创建一个Maven工程

       创建一个maven工程,取名为mybatis-my

1.2 导入依赖包

       在pom.xml文件中,导入相应的依赖包: 

    <dependency>
        <groupId>org.dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>2.1.1</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.16</version>
    </dependency>

说明:这里使用dom4j进行解析xml文件,mysql-connector-java这是mysql的数据库驱动。

 

1.3 配置文件

       Mybatis-config.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>

    <properties resource="jdbc.properties" />

    <mappers>
        <mapper resource="mappers/DemoMapper.xml"/>
    </mappers>
</configuration>

说明:这里为了更好的理解,只配置了一小部分,其它的配置读取原理是一样的。

       jdbc.properties文件:

url:jdbc:mysql://127.0.0.1:3306/test
driver:com.mysql.cj.jdbc.Driver
username:root
password:root

说明:这是连接数据库最基本的信息。

       DemoMapper.xml:

<?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="com.kfit.mybatis.demo.mapper.DemoMapper">
    <select id="getById" resultType="com.kfit.mybatis.demo.bean.Demo">
           select *from demo where id = ?
    </select>

    <select id="getAll" resultType="com.kfit.mybatis.demo.bean.Demo">
           select *from demo
    </select>
</mapper>

说明:在mybatis-config.xml并没有配置typeAliases,所以这里就不能识别我们的实体类了,这里使用实体类的全路径进行识别,方便之后进行解析。

 

 

1.4 接口和基本的类

       这里我们先准备一下几个常用的接口和一些构造类:

(1)SqlSessionFactoryBuilder:

 

package com.kfit.mybatis.session;

public class SqlSessionFactoryBuilder {

}

说明:SqlSessionFactoryBuilder主要是读取配置文件信息,进行构造SqlSessionFactory。

(2)SqlSessionFactory:

 

package com.kfit.mybatis.session;

public interface SqlSessionFactory {

}

 

说明:SqlSessionFactory主要是管理SqlSession。

(3)SqlSession

 

package com.kfit.mybatis.session;

public interface SqlSession {

}

说明:SqlSession主要是进行数据库操作的。

 

二、配置文件的读取

2.1 配置类构建

       在读取配置文件xml和properties,那么就需要对应的类进行存储这些配置文件,

我们使用JdbcProperties进行存储数据库相关的信息,使用MapperStatement存储mapper.xml对应的配置信息,使用Configuration进行统一的管理mybatis-config.xml配置信息,具体的代码如下:

(1)JdbcProperties

package com.kfit.mybatis.config;

public class JdbcProperties {
    private String url;
    private String driver;
    private String username;
    private String password;
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getDriver() {
        return driver;
    }
    public void setDriver(String driver) {
        this.driver = driver;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }

}

 

说明:这里配置的是上面对应的jdbc.properties配置文件的字段。

(2)MapperStatement

 

package com.kfit.mybatis.config;

public class MapperStatement {
    private String id;//由二位坐标构成的ID=namespave.id
    private String sql;//sql语句
    private String resultType;//返回类型
    private String queryType;//查询语句类型

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getSql() {
        return sql;
    }
    public void setSql(String sql) {
        this.sql = sql;
    }
    public String getResultType() {
        return resultType;
    }
    public void setResultType(String resultType) {
        this.resultType = resultType;
    }
    public String getQueryType() {
        return queryType;
    }
    public void setQueryType(String queryType) {
        this.queryType = queryType;
    }
}

说明:这里对应的是Mapper.xml对应的配置,在这里只是配置了几个基本的,目前未包括全部。

(3)Configuration

 

package com.kfit.mybatis.config;

import java.util.HashMap;
import java.util.Map;

public class Configuration {
    private JdbcProperties jdbcProperties;
    private Map<String,MapperStatement> mapperMap = new HashMap<String, MapperStatement>();

    public void addMapperStatement(MapperStatement mapperStatement) {
        mapperMap.put(mapperStatement.getId(),mapperStatement);
    }

    public MapperStatement getMapperStatement(String id) {
        return mapperMap.get(id);
    }

    public JdbcProperties getJdbcProperties() {
        return jdbcProperties;
    }

    public void setJdbcProperties(JdbcProperties jdbcProperties) {
        this.jdbcProperties = jdbcProperties;
    }

}

说明:Configuration这里就是统一进行管理配置以及提供一些对配置基本的操作方法。

 

2.2 配置文件读取

       配置文件的读取,通过SqlSessionFactoryBuilder进行读取的,在SqlSessionFactoryBuilder中提供build方法构建返回SqlSessionFactory。SqlSessionFactory上面定义的是一个接口,我们需要定义默认的实现,在这个实现的构造方法中需要传入Configuration配置参数。

(1)SqlSessionFactory的默认实现类DefaultSqlSessionFactory

package com.kfit.mybatis.session.impl;

import com.kfit.mybatis.config.Configuration;
import com.kfit.mybatis.session.SqlSessionFactory;

public class DefaultSqlSessionFactory implements SqlSessionFactory{

    private Configuration configuration;

    public DefaultSqlSessionFactory(Configuration configuration) {
        this.configuration = configuration;
    }

    public Configuration getConfiguration() {
        return configuration;
    }
    public void setConfiguration(Configuration configuration) {
        this.configuration = configuration;
    }

}

 

说明:目前这个类当中并没有什么实现,只是接收了configuration,在之后我们会编写openSession的方法获取到一个SqlSession。

(2)SqlSessionFactoryBuilder

 

 

package com.kfit.mybatis.session;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Properties;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.kfit.mybatis.config.Configuration;
import com.kfit.mybatis.config.JdbcProperties;
import com.kfit.mybatis.config.MapperStatement;
import com.kfit.mybatis.session.impl.DefaultSqlSessionFactory;

public class SqlSessionFactoryBuilder {

    public SqlSessionFactory build(InputStream inputStream) {

        SAXReader reader = new SAXReader();
        Document document=null;
        Configuration configuration = new Configuration();
        try {
            document = reader.read(inputStream);
            Element configEle = document.getRootElement();

            //读取jdbc的配置文件,然后加载jdbc配置信息
            Element propertiesEle = configEle.element("properties");
            String jdbcPropertiesPath = propertiesEle.attributeValue("resource");
            loadProperties(configuration,jdbcPropertiesPath);

            //mapper的读取
            Element mappersEle = configEle.element("mappers");
            List<Element> mapperEleList = mappersEle.elements("mapper");
            for(Element ele:mapperEleList) {
                String mapperPath = ele.attributeValue("resource");
                loadMapperStatement(configuration,mapperPath);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return new DefaultSqlSessionFactory(configuration);
    }



    /**
     * 加载配置信息
     * @param configuration
     */
    private void loadProperties(Configuration configuration,String jdbcPropertiesPath) {
        InputStream inputStream =  this.getClass().getClassLoader().getResourceAsStream(jdbcPropertiesPath);
        Properties properties = new Properties();
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        JdbcProperties jdbcProperties = new JdbcProperties();
        jdbcProperties.setUrl(properties.getProperty("url"));
        jdbcProperties.setDriver(properties.getProperty("driver"));
        jdbcProperties.setPassword(properties.getProperty("password"));
        jdbcProperties.setUsername(properties.getProperty("username"));

        configuration.setJdbcProperties(jdbcProperties);
    }

    /**
     * 加载mapper信息
     * @param configuration
     * @param mapperPath
     */
    private void loadMapperStatement(Configuration configuration, String mapperPath) {
        MapperStatement  mapperStatement = null;

        SAXReader reader = new SAXReader();
        Document document=null;
        try {
            InputStream inputStream =  this.getClass().getClassLoader().getResourceAsStream(mapperPath);
            document = reader.read(inputStream);
            Element rootEle = document.getRootElement();

             //获取命名空间
            String namespace = rootEle.attributeValue("namespace");

            for(Element ele:rootEle.elements()) {
                mapperStatement = new MapperStatement();
                mapperStatement.setQueryType(ele.getName());
                mapperStatement.setId(namespace+"."+ele.attributeValue("id"));
                mapperStatement.setResultType(ele.attributeValue("resultType"));
                mapperStatement.setSql(ele.getText());
                configuration.addMapperStatement(mapperStatement);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

}

 

 

说明(这个就是解析配置文件的核心代码):

       这里方法的入口是build,在build中首先使用dom4j的SAXReader读取配置mybatis-config.xml文件,接着就是依次解析出来jdbc.properties文件的数据库连接配置信息存放到JdbcProperties和mapper.xml的信息存放到MapperStatement,而JdbcProperties和MapperStatement放到Configuration进行管理,最后实例化一个DefaultSqlSessionFactory进行返回。

 

2.3 测试SqlSessionFactory

       我们在SqlSessionFactory接口中加入一个获取Configuration的方法:

 

public interface SqlSessionFactory {
    public Configuration getConfiguration();
}

       写一个main方法来测试吧:

 

public class App {
    public static void main(String[] args) {
        String resource = "mybatis-config.xml";
        InputStream inputStream = App.class.getClassLoader().getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        System.out.println(sqlSessionFactory);
        System.out.println(sqlSessionFactory.getConfiguration().getJdbcProperties().getUrl());

    }
}

执行可以看到打印信息:

com.kfit.mybatis.session.impl.DefaultSqlSessionFactory@7229724f

jdbc:mysql://127.0.0.1:3306/test

       好了今天就先到这里,写的都有点脑袋发蒙了。

        SqlSession又是如何构建的呢?欲知详情,下回分解。

我就是我,是颜色不一样的烟火。
我就是我,是与众不同的小苹果。

à悟空学院:http://t.cn/Rg3fKJD

 

SpringBoot视频:http://t.cn/R3QepWG

Spring Cloud视频:http://t.cn/R3QeRZc

SpringBoot Shiro视频:http://t.cn/R3QDMbh

SpringBoot交流平台:http://t.cn/R3QDhU0

SpringData和JPA视频:http://t.cn/R1pSojf

SpringSecurity5.0视频:http://t.cn/EwlLjHh

Sharding-JDBC分库分表实战:http://t.cn/E4lpD6e