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

Posted IT老刘

tags:

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


本章接着上一章手写MyBatis,主要这集中在sqlSession对象的获取!

1.自定义SqlSessionFactory接口

SqlSessionFactory接口是获取session工厂的规范:

package org.apache.ibatis.session;

public interface SqlSessionFactory {

    SqlSession openSession();
}

2.自定义SqlSession接口

package org.apache.ibatis.session;

import java.util.List;

public interface SqlSession {


    /**
     * 查询所有
     *
     * @param statementId sql唯一id
     * @param params      sql有可能是模糊查询,传可变参数
     * @param <E>         泛型
     * @return List集合
     */
    <E> List<E> selectList(String statementId, Object... params) throws Exception;

    /**
     * 根据条件查询单个
     *
     * @param statementId sql唯一id
     * @param params      sql有可能是模糊查询,传可变参数
     * @param <T>         泛型
     * @return 某一对象
     */
    <T> T selectOne(String statementId, Object... params) throws Exception;
    

    /**
     * 更新操作
     *
     * @param statementId sql唯一id
     * @param params      可变参数
     * @return 更新条数
     */
    <T> T update(String statementId, Object... params) throws Exception;
    

    /**
     * 为Dao层接口生成代理实现类
     *
     * @param mapperClass 字节码
     * @param <T>         泛型
     * @return 某一对象
     */
    <T> T getMapper(Class<?> mapperClass) throws Exception;
}

3.自定义DefaultSqlSession实现类

DefaultSqlSession类为SqlSession接口的实现类,此处暂时先重写getMapper方法,通过JDK动态代理生成Dao层接口实例对象!

public class CommandType {

    public final static String[] sqlCommand = {"insert", "update", "delete"};

}
package org.apache.ibatis.session;

import org.apache.ibatis.configration.Configuration;

import java.lang.reflect.*;
import java.util.Arrays;
import java.util.List;

public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

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


    @Override
    public <E> List<E> selectList(String statementId, Object... params) throws Exception {
        return null;
    }

    @Override
    public <T> T selectOne(String statementId, Object... params) throws Exception {
        return null;
    }

    @Override
    public <T> T update(String statementId, Object... params) throws Exception {
        return null;
    }

    @Override
    public <T> T getMapper(Class<?> mapperClass) throws Exception {

        // 使用JDK动态代理来为Dao层接口生成代理对象,并返回。
        Object proxyInstance = Proxy.newProxyInstance(mapperClass.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                /**
                 * 底层都还是去执行JDBC代码
                 * 根据不同情况来调用findAll或者findByCondition方法
                 * 准备参数:
                 * 1.statementId: sql语句的唯一标识 nnamespace.id = 接口全限定名.方法名
                 */
                // 方法名
                String methodName = method.getName();
                String className = method.getDeclaringClass().getName();

                String statementId = className + "." + methodName;

                // 准备参数 2.params:args
                // 获取被调用方法的返回值类型
                Type genericReturnType = method.getGenericReturnType();
                if (Arrays.asList(CommandType.sqlCommand).contains(methodName)) {
                    return update(statementId, args);
                }
                // 判断是否进行了泛型类型参数化
                if (genericReturnType instanceof ParameterizedType) {
                    List<Object> objects = selectList(statementId, args);
                    return objects;
                }
                return selectOne(statementId, args);
            }
        });
        return (T) proxyInstance;
    }
}

4.自定义DefaultSqlSessionFactory

package org.apache.ibatis.session;

import org.apache.ibatis.configration.Configuration;

public class DefaultSqlSessionFactory implements SqlSessionFactory {

    private Configuration configuration;

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

    @Override
    public SqlSession openSession() {
        return new DefaultSqlSession(configuration);
    }

}

5.自定义SqlSessionFactoryBuilder

SqlSessionFactoryBuilder类的作用是获取SqlSessionFactory

package org.apache.ibatis.session;

import org.apache.ibatis.configration.Configuration;
import org.apache.ibatis.parser.XMLConfigBuilder;
import org.dom4j.DocumentException;

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

public class SqlSessionFactoryBuilder {

    public SqlSessionFactory build(InputStream in) throws DocumentException, PropertyVetoException {
        // 1.使用dom4j解析配置文件,将解析出来的内容封装到Configuration
        XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder();
        Configuration configuration = xmlConfigBuilder.parseConfig(in);

        // 2.创建SqlSessionFactory对象:工厂类:生产SqlSession:会话对象
        DefaultSqlSessionFactory defaultSqlSessionFactory = new DefaultSqlSessionFactory(configuration);
        return defaultSqlSessionFactory;
    }
}

至此为止sqlsession构建完毕!

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

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

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

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

大厂程序员,手写Mybatis

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

了解mybatis源码手写mybatis