《Java手写系列》-手写MyBatis框架

Posted IT老刘

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Java手写系列》-手写MyBatis框架相关的知识,希望对你有一定的参考价值。


下面接着第一章内容,手写MyBatis框架!

1.自定义Resources类

Resources类的作用是获取一个类加载器,根据配置文件的路径,将配置文件加载成字节输入流,存储在内存中。

package org.apache.ibatis.io;

import java.io.InputStream;

public class Resources {

    /**
     * 根据配置文件的路径,将配置文件加载成字节输入流,存储在内存中。
     * @param path 文件路径
     * @return     字节流
     */
    public static InputStream getResourceAsStream(String path){
        InputStream resourceAsStream = Resources.class.getClassLoader().getResourceAsStream(path);
        return resourceAsStream;
    }
}

2.自定义MappedStatement类

MappedStatement类作用是封装UserMapper.xml文件解析之后的SQL语句信息,在底层框架可以使用Dom4J进行解析!

package org.apache.ibatis.configration;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MappedStatement {

    // id标识
    private String id;

    // 返回值类型
    private String resultType;

    // 参数值类型
    private String parameterType;

    // sql语句
    private String sql;
}

3.自定义Configuration类

Configuration类是MyBatis框架的SQL配置封装类,后期使用Dom4J进行解析

package org.apache.ibatis.configration;

import com.google.common.collect.Maps;

import javax.sql.DataSource;
import java.util.Map;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Configuration {

    /**
     * 数据源对象
     */
    private DataSource dataSource;

    /**
     * key:statementId
     * value:封装好的MappedStatement
     */
    Map<String,MappedStatement> mappedStatementMap= Maps.newHashMap();
}

4.解析配置文件

4.1.解析mapper.xml

自定义类XMLMapperBuilder

package org.apache.ibatis.parser;

import com.google.common.collect.Lists;
import org.apache.ibatis.configration.Configuration;
import org.apache.ibatis.configration.MappedStatement;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

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

/**
 * mapper.xml文件解析类
 */
public class XMLMapperBuilder {

    private Configuration configuration;

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

    public void parse(InputStream in) throws DocumentException {
        Document document = new SAXReader().read(in);
        Element rootElement = document.getRootElement();
        String namespace = rootElement.attributeValue("namespace");

        List<Element> selectList = rootElement.selectNodes("//select");
        List<Element> insertList = rootElement.selectNodes("//insert");
        List<Element> updateList = rootElement.selectNodes("//update");
        List<Element> deleteList = rootElement.selectNodes("//delete");
        List<Element> allList = Lists.newArrayList();
        allList.addAll(selectList);
        allList.addAll(insertList);
        allList.addAll(updateList);
        allList.addAll(deleteList);
        for (Element element : allList) {
            String id = element.attributeValue("id");
            String resultType = element.attributeValue("resultType");
            String parameterType = element.attributeValue("parameterType");
            String sqlText = element.getTextTrim();
            MappedStatement mappedStatement = new MappedStatement();
            mappedStatement.setId(id);
            mappedStatement.setResultType(resultType);
            mappedStatement.setParameterType(parameterType);
            mappedStatement.setSql(sqlText);

            String key = namespace + "." + id;
            configuration.getMappedStatementMap().put(key, mappedStatement);
        }
    }
}

测试mapper.xml解析

package com.bruce.test;

import org.apache.ibatis.configration.Configuration;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.parser.XMLMapperBuilder;
import org.dom4j.DocumentException;
import org.junit.Test;

import javax.annotation.Resource;
import java.io.InputStream;

public class TestMapperparser {

    @Test
    public void test1(){
        try {
            Configuration configuration=new Configuration();
            InputStream resourceAsStream = Resources.getResourceAsStream("mappers/UserMapper.xml");
            XMLMapperBuilder xmlMapperBuilder=new XMLMapperBuilder(configuration);
            xmlMapperBuilder.parse(resourceAsStream);
            System.out.println("mapper.xml解析完毕");
            System.out.println(configuration);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }
}

4.2.解析mybatis-config.xml

自定义类XMLConfigBuilder

package org.apache.ibatis.parser;

import org.apache.ibatis.configration.Configuration;

/**
 * 解析mybatis-config.xml
 */
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.ibatis.io.Resources;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.beans.PropertyVetoException;
import java.io.InputStream;
import java.util.List;
import java.util.Properties;

public class XMLConfigBuilder {

    private Configuration configuration;

    public XMLConfigBuilder() {
        this.configuration = new Configuration();
    }
    /**
     * 该方法就是使用dom4j对配置文件进行解析,封装成Configuration对象
     * @param in 字节输入流
     * @return   Configuration
     */
    public Configuration parseConfig(InputStream in) throws DocumentException, PropertyVetoException {
        Document document = new SAXReader().read(in);
        // <configuration>
        Element rootElement = document.getRootElement();
        List<Element> list = rootElement.selectNodes("//property");
        Properties properties = new Properties();
        for (Element element : list) {
            String name = element.attributeValue("name");
            String value = element.attributeValue("value");
            properties.setProperty(name, value);
        }

        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        comboPooledDataSource.setDriverClass(properties.getProperty("driverClass"));
        comboPooledDataSource.setJdbcUrl(properties.getProperty("jdbcUrl"));
        comboPooledDataSource.setUser(properties.getProperty("username"));
        comboPooledDataSource.setPassword(properties.getProperty("password"));

        configuration.setDataSource(comboPooledDataSource);

        // mapper.xml解析:拿到路径--字节输入流--dom4j进行解析
        List<Element> mapperList = rootElement.selectNodes("//mapper");
        for (Element element : mapperList) {
            String mapperPath = element.attributeValue("resource");
            InputStream resourceAsStream = Resources.getResourceAsStream(mapperPath);
            XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configuration);
            xmlMapperBuilder.parse(resourceAsStream);
        }

        return configuration;
    }
}

测试mybatis-config.xml解析类:

package com.bruce.test;

import org.apache.ibatis.configration.Configuration;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.parser.XMLConfigBuilder;
import org.dom4j.DocumentException;
import org.junit.Test;

import java.beans.PropertyVetoException;
import java.io.InputStream;

public class TestConfigParser {

    @Test
    public void test1(){
        try {
            XMLConfigBuilder xmlConfigBuilder=new XMLConfigBuilder();
            InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
            xmlConfigBuilder.parseConfig(resourceAsStream);
            System.out.println("config.xml解析完毕");
            System.out.println(xmlConfigBuilder);
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

以上是关于《Java手写系列》-手写MyBatis框架的主要内容,如果未能解决你的问题,请参考以下文章

《Java手写系列》-手写MyBatis框架

《Java手写系列》-手写MyBatis框架

手写MyBatis,纯手工打造开源框架(第四篇:决胜千里)- 第272篇

大厂程序员,手写Mybatis

手写Mybatis,彻底搞懂框架原理

了解mybatis源码手写mybatis