学习Mybatis(7):Mybatis运行原理源码分析

Mybatis运行主要有三步:

1)创建SqlSessionFactory工厂对象

一般使用的方法是使用SqlSessionFactoryBuilder生成器的build方法加载配置文件生成:

SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis_config.xml"));

实际调用的是build方法的一个三参数重载方法,该方法使用XMLConfigBuilder类对配置文件进行解析,然后创建了一个DefaultSqlSessionFactory对象:

    public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        SqlSessionFactory var5;
        try {
            XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
            var5 = this.build(parser.parse());
        } catch (Exception var14) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
        } finally {
            ErrorContext.instance().reset();

            try {
                inputStream.close();
            } catch (IOException var13) {
            }

        }

        return var5;
    }

    public SqlSessionFactory build(Configuration config) {
        return new DefaultSqlSessionFactory(config);
    }

parse方法实际调用了parseConfiguration方法,对每一种标签分别进行解析,并将解析结果存入父类BaseBuilder的configure对象中:

    public Configuration parse() {
        if (this.parsed) {
            throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        } else {
            this.parsed = true;
            this.parseConfiguration(this.parser.evalNode("/configuration"));
            return this.configuration;
        }
    }

    private void parseConfiguration(XNode root) {
        try {
            this.propertiesElement(root.evalNode("properties"));
            this.typeAliasesElement(root.evalNode("typeAliases"));
            this.pluginElement(root.evalNode("plugins"));
            this.objectFactoryElement(root.evalNode("objectFactory"));
            this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
            this.settingsElement(root.evalNode("settings"));
            this.environmentsElement(root.evalNode("environments"));
            this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
            this.typeHandlerElement(root.evalNode("typeHandlers"));
            this.mapperElement(root.evalNode("mappers"));
        } catch (Exception var3) {
            throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
        }
    }
public abstract class BaseBuilder {
    protected final Configuration configuration;
    ……
}

parseConfiguration中调用的各方法都差不多,就是对DOM树进行解析

2)创建SqlSession对象

SqlSession对象通过SqlSessionFactory的工厂方法openSession产生:

SqlSession sqlSession=sqlSessionFactory.openSession();

此方法还可以接受一些参数,如:

  • boolean autoCommit:是否自动提交事务,默认false
  • TransactionIsolationLevel level:事务隔离级别,默认null(为空时会从Connection获取事务隔离级别)
  • ExecutorType execType:Executor类型,默认SimpleExecutor

接受以上三个参数的openSession方法会调用openSessionFromDataSource方法进一步处理

还可以接受一个Connection对象,从连接中获取以上属性进行配置,过程差不多,以openSessionFromDataSource为例:

    private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;

        DefaultSqlSession var8;
        try {
            Environment environment = this.configuration.getEnvironment();
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            Executor executor = this.configuration.newExecutor(tx, execType);
            var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
        } catch (Exception var12) {
            this.closeTransaction(tx);
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);
        } finally {
            ErrorContext.instance().reset();
        }

        return var8;
    }

可以看到方法中创建了一个DefaultSqlSession对象并进行组装

3)创建Mapper对象

使用getMapper方法,定义如下:

    public <T> T getMapper(Class<T> type) {
        return this.configuration.getMapper(type, this);
    }

实际是从configuration中取出Mapper对象:

    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        return this.mapperRegistry.getMapper(type, sqlSession);
    }

MapperRegistry类内部使用一个HashMap存储MapperProxyFactory对象(Mapper的类型为key)

MapperProxyFactory是在创建SqlSessionFactory时,在parseConfiguration -> mapperElement方法中逐个添加到MapperRegistry的:

    private void mapperElement(XNode parent) throws Exception {
        ……
        Class<?> mapperInterface = Resources.classForName(mapperClass);
        this.configuration.addMapper(mapperInterface);
        ……
    }

addMapper方法只会对接口进行处理。

在getMapper方法中创建Mapper代理对象:

    private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();

    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
        if (mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        } else {
            try {
                return mapperProxyFactory.newInstance(sqlSession);
            } catch (Exception var5) {
                throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
            }
        }
    }

这里看起来创建的是MapperProxyFactory的代理,实际上是用了重载函数的障眼法隐藏了实现:

    protected T newInstance(MapperProxy<T> mapperProxy) {
        return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
    }

    public T newInstance(SqlSession sqlSession) {
        MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return this.newInstance(mapperProxy);
    }

MapperProxy才是真正实现了InvocationHandler的动态代理类,其invoke方法有一个分支判断:

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (Object.class.equals(method.getDeclaringClass())) {
            try {
                return method.invoke(this, args);
            } catch (Throwable var5) {
                throw ExceptionUtil.unwrapThrowable(var5);
            }
        } else {
            MapperMethod mapperMethod = this.cachedMapperMethod(method);
            return mapperMethod.execute(this.sqlSession, args);
        }
    }

意思是:

如果是创建代理对象(Proxy.newProxyInstance方法最终是向newInstance方法传递了一个Object数组,所以会进入if分支),就按照动态代理流程往下走

如果是方法调用(比如调用Mapper的某个方法),就调用executor方法执行(该方法根据MapperMethod的类型再调用sqlSession封装的CRUD方法),代码如下:

    public Object execute(SqlSession sqlSession, Object[] args) {
        Object param;
        Object result;
        if (SqlCommandType.INSERT == this.command.getType()) {
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
        } else if (SqlCommandType.UPDATE == this.command.getType()) {
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
        } else if (SqlCommandType.DELETE == this.command.getType()) {
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
        } else {
            if (SqlCommandType.SELECT != this.command.getType()) {
                throw new BindingException("Unknown execution method for: " + this.command.getName());
            }

            if (this.method.returnsVoid() && this.method.hasResultHandler()) {
                this.executeWithResultHandler(sqlSession, args);
                result = null;
            } else if (this.method.returnsMany()) {
                result = this.executeForMany(sqlSession, args);
            } else if (this.method.returnsMap()) {
                result = this.executeForMap(sqlSession, args);
            } else {
                param = this.method.convertArgsToSqlCommandParam(args);
                result = sqlSession.selectOne(this.command.getName(), param);
            }
        }

        if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
            throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
        } else {
            return result;
        }
    }

代码看着很多,但是都是命令模式的各个分支,做的事情都是组装参数和结果集,无非是根据查询需要调用不同的组装方法而已

举例:

UserMapper::getUser方法,其sql语句为:

select * from User where id=#{id};

是一个select方法,另外由于id为主键,查询结果必然只有一条,所以其command类型为SELECT,method对象(方法特征)的returnsMany、returnsVoid、returnsMap属性可推断均为false,执行的必然是selectOne方法所在分支

在此打断点DEBUG,确实停住了,并且相关属性完全符合推断:

猜你喜欢

转载自blog.csdn.net/u010670411/article/details/85049438
今日推荐