Mybatis的源码分析


在这里插入图片描述在这里插入图片描述

一.SqlSessionFactory的创建

SqlSessionFactoryBuilder.class
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    SqlSessionFactory var5;
    try {
        //建立一个配置解析器,用于解析mybatis的配置文件以及mapper配置文件
        XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
        //通过解析得到的configuration对象创建一个DefaultSqlSessionFactory对象
        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) {
        }

}
XmlConfigBuilder.class
//解析xml中的每一个配置信息,并且解析mapper的xml文件
private void parseConfiguration(XNode root) {
    try {
        this.propertiesElement(root.evalNode("properties"));
        Properties settings = this.settingsAsProperties(root.evalNode("settings"));
        this.loadCustomVfs(settings);
        this.loadCustomLogImpl(settings);
        this.typeAliasesElement(root.evalNode("typeAliases"));
        this.pluginElement(root.evalNode("plugins"));
        this.objectFactoryElement(root.evalNode("objectFactory"));
        this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
        this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
        this.settingsElement(settings);
        this.environmentsElement(root.evalNode("environments"));
        this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
        this.typeHandlerElement(root.evalNode("typeHandlers"));
        //解析mapper
        this.mapperElement(root.evalNode("mappers"));
    } catch (Exception var3) {
        throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
    }
}
XmlConfigBuilder.class
private void mapperElement(XNode parent) throws Exception {
    if (parent != null) {
        Iterator var2 = parent.getChildren().iterator();
        while(true) {
            while(var2.hasNext()) {
                XNode child = (XNode)var2.next();
                String resource;
                //若标签为package的解析
                if ("package".equals(child.getName())) {
                    resource = child.getStringAttribute("name");
                    this.configuration.addMappers(resource);
                } else {
                    //标签为mapper
                    resource = child.getStringAttribute("resource");
                    String url = child.getStringAttribute("url");
                    String mapperClass = child.getStringAttribute("class");
                    XMLMapperBuilder mapperParser;
                    InputStream inputStream;
                    //对resource进行解析
                    if (resource != null && url == null && mapperClass == null) {
                        ErrorContext.instance().resource(resource);
                        inputStream = Resources.getResourceAsStream(resource);
                        mapperParser = new XMLMapperBuilder(inputStream, this.configuration, resource, this.configuration.getSqlFragments());
                        mapperParser.parse();
                         //对url进行解析
                    } else if (resource == null && url != null && mapperClass == null) {
                       .......
                    } else {
                         //对class进行解析
                        if (resource != null || url != null || mapperClass == null) {
                            throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
                        }

                        Class mapperInterface = Resources.classForName(mapperClass);
                        this.configuration.addMapper(mapperInterface);
                    }
                }
            }

进入到mapperParse.parse方法,并深入源码,可以看到

private void buildStatementFromContext(List list, String requiredDatabaseId) {
    Iterator var3 = list.iterator();

    while(var3.hasNext()) {
        XNode context = (XNode)var3.next();
        XMLStatementBuilder statementParser = new XMLStatementBuilder(this.configuration, this.builderAssistant, context, requiredDatabaseId);

        try {
            //通过此方法会创建Mapper中每个SQL标签的MappedStatement对象
            statementParser.parseStatementNode();
        } catch (IncompleteElementException var7) {
            this.configuration.addIncompleteStatement(statementParser);
        }
    }

}



    回到SqlSessionFactoryBuilder中

//最后通过此方法获取一个DefaultSqlSessionFactory对象
public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
}



二.SqlSession的创建



DefaultSqlSessionFactory.class
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);
         //通过配置信息,执行器和是否自动提交这三个信息获得一个DefaultSqlSession 
        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;
}

   注意在创建执行器时或对生成的执行器进行一个装饰,通过装饰模式,将刚才产生的executor 包装成一个更加强大的 executor。
   作用:以后 如果我们要给MyBatis写自己的插件, 就可以通过拦截器实现。
   插件开发: 1写插件 2放入拦截器

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    。。。。。。。
  Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
  return executor;
}



三.获取Mapper的代理对象



DefaultSqlSession.class
public  T getMapper(Class type) {
    return this.configuration.getMapper(type, this);
}
Configuration.class
public  T getMapper(Class type, SqlSession sqlSession) {
    return this.mapperRegistry.getMapper(type, sqlSession);
}
MapperRegistry.class
public  T getMapper(Class type, SqlSession sqlSession) {
    //通过knownMappers获取一个MapperProxyFactory对象
    MapperProxyFactory mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
    if (mapperProxyFactory == null) {
        throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    } else {
        try {
            //返回一个mapperProxy实例
            return mapperProxyFactory.newInstance(sqlSession);
        } catch (Exception var5) {
            throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
        }
    }
}

   跟进,可以在MapperProxyFactory.class中获取一个mapperProxy对象

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

从这里可以看到:
(1)先从knownMappers的map集合中获取MapperProxyFactory对象,knownMappers怎么有MapperProxyFactory对象呢?这个是从启动时,扫描出来的,有兴趣的可以看看启动时,扫描mapper。
(2)通过mapperProxyFactory.newInstance(sqlSession);利用了jdk动态代理生成了mapper的代理类MapperProxy




四.执行增删改查



执行增删改查,其实是调用一个MapperProxy(实现了Serializable和InvocationHandle接口)的invoke方法
接下来会调用cachedMapperMethod(method)方法通过Method从缓存中获取一个MapperMethod,如果缓存中没有,则创建一个。接下来会执行这个mapperMethod,参数为sqlsession和args,其中sqlSession存有configuration和executor。进入executor方法中

MapperProxy.class
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   。。。。。。
   //先从缓存中获取当前方法的MapperMethod对象,
   //缓存中存在则直接获取,没有则创建一个。源码看下方
    MapperMethod mapperMethod = this.cachedMapperMethod(method);
    //调用mapperMethod的execute方法
    return mapperMethod.execute(this.sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
    return (MapperMethod)this.methodCache.computeIfAbsent(method, (k) -> {
        return new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
    });
}

会根据MapperMethod获取sql语句的类型从而进行不同的处理。其中convertArgsToSqlCommandParam(args)会根据args返回一个对象:
    如果参数为null,返回一个null;
    如果参数个数为1,则返回第一个;
    如果参数为多个,则多个参数放入一个Map集合中,并返回。
select方法执行 result = sqlSession.selectOne(this.command.getName(), param);
(此方法在DefaultSqlSession中具体实现)。

MapperMethod.class
public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    Object param;
    switch(this.command.getType()) {
    case INSERT:
        param = this.method.convertArgsToSqlCommandParam(args);
        result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
        break;
    case UPDATE:
        param = this.method.convertArgsToSqlCommandParam(args);
        result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
        break;
    case DELETE:
        param = this.method.convertArgsToSqlCommandParam(args);
        result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
        break;
    case SELECT:
        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 if (this.method.returnsCursor()) {
            result = this.executeForCursor(sqlSession, args);
        } else {
            //将参数封装成一个Map集合
            param = this.method.convertArgsToSqlCommandParam(args);
            //执行selectOne方法
            result = sqlSession.selectOne(this.command.getName(), param);
            if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {
                result = Optional.ofNullable(result);
            }
        }
        break;
    case FLUSH:
        result = sqlSession.flushStatements();
        break;
    default:
        throw new BindingException("Unknown execution method for: " + this.command.getName());
    }

    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;
    }
}

这里的sql语句是select,跟进selectOne方法

DefaultSqlSession.class
public  T selectOne(String statement, Object parameter) {
    //不管是查询一个还是查询多个都会进入selectList中
    List list = this.selectList(statement, parameter);
    if (list.size() == 1) {
        //根据最终返回的一个List集合获取一个数据
        return list.get(0);
        //如果数据大于一个会报错,因为这里是selectOne
    } else if (list.size() > 1) {
        throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
    } else {
        return null;
    }
}

进入selectList方法中

DefaultSqlSession.class
public  List selectList(String statement, Object parameter, RowBounds rowBounds) {
    List var5;
    try {
        //会根据传入的statement(此参数通过MapperMethod.getName()获取),
        //从configuration中获取MappedStatement
        MappedStatement ms = this.configuration.getMappedStatement(statement);
        //执行器进行查询(CachingExecutor)
        var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception var9) {
        throw ExceptionFactory.wrapException("Error querying database.  Cause: " + var9, var9);
    } finally {
        ErrorContext.instance().reset();
    }

    return var5;
}.

进入query(位于CachingExecutor.class)中

CachingExecutor.class
public  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
   //boundSql :将我们写的SQL 和 参数值进行了拼接后的对象,即最终能被真正执行的SQL
     BoundSql boundSql = ms.getBoundSql(parameterObject);
     //生成一个缓存
    CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);
    //继续进行查询
    return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}


CachingExecutor.class
public  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    Cache cache = ms.getCache();
    //如果缓存不为空,则直接获取
    if (cache != null) {
        this.flushCacheIfRequired(ms);
        if (ms.isUseCache() && resultHandler == null) {
            this.ensureNoOutParams(ms, boundSql);
            List list = (List)this.tcm.getObject(cache, key);
            if (list == null) {
                list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
                this.tcm.putObject(cache, key, list);
            }

            return list;
        }
    }
    //继续进行查询(此方法位于BaseExecutor.class中)
    return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

获取缓存,如果缓存存在,直接获取;否则,通过delegate.query()创建。(方法位于BaseExecutor.class中)

BaseExecutor.class
try{
++this.queryStack;
list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
if (list != null) {
    //直接从缓存中获取
    this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
    //通过从数据库中查找
    list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
}finally

先从本地缓存中获取,如果没有则调用queryFromDatabase()方法从数据库查找

BaseExecutor.class
private  List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    //设置缓存
    this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);

    List list;
    try {
        //进入此方法,此方法由SimpleExecutor实现
        list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
        this.localCache.removeObject(key);
    }

    this.localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
        this.localOutputParameterCache.putObject(key, parameter);
    }

    return list;
}

进入doQuery()方法(此方法在SimpleExecutor.class中)
mybatis使用的jdbc对象是PreparedStatement

SimpleExecutor.class
public  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;

    List var9;
    try {
        Configuration configuration = ms.getConfiguration();
        //会通过我们传入的参数创建一个StatementHandler对象,并且
        //会通过interceptorChain进行装饰并返回一个增强的StatementHandler
        //PrepareStatementHandler.class
        StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
       //获取一个Statement对象
         stmt = this.prepareStatement(handler, ms.getStatementLog());
         //通过获取的Statement进行查询
        var9 = handler.query(stmt, resultHandler);
    } finally {
        this.closeStatement(stmt);
    }

    return var9;
}

进入prepareStatement()方法

SimpleExecutor.class
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Connection connection = this.getConnection(statementLog);
    //通过PrepareStatementHandler的prepare方法创建一个statement
    Statement stmt = handler.prepare(connection, this.transaction.getTimeout());
    //会将一个Statement转为PreparedStatement
    //在PrepareStatementHandler中进行,
    //涉及ParameterHandler.class,处理参数的控制器
    handler.parameterize(stmt);  
    return stmt;
}
PrepareStatementHandler.class
public void parameterize(Statement statement) throws SQLException {
    this.parameterHandler.setParameters((PreparedStatement)statement);
}

进入handler.query(stmt, resultHandler);方法获得List结果集

PrepareStatementHandler.class
public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement)statement;
    ps.execute();
    //resultSetHandler,处理结果集的控制器
    return this.resultSetHandler.handleResultSets(ps);
}






转自我以前在CSDN写的一篇mybatis源码学习记录


文章作者: 小莫の咕哒君
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 小莫の咕哒君 !
评论
  目录