前言
之前出了一套《吃透Mybatis源码》,本篇文章是整体性的概括一下Mybatis的底层实现流程,以《66个类手撸Mybatis》为基础进行讲解,代码已经上传到Gitee,希望对你有所帮助
架构说明
cg-mybatis
- cg-mybatis-core : mybatis 核心
- cg-mybatis-example : 测试用例
下面是Mybatis源码执行大致流程图
// 创建 SqlSessionFactoryBuilder 对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 通过核心配置文件所对应的字节输入流创建工厂类 SqlSessionFactory ,生产SqlSession 对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build("mybatis-config.xml");
SqlSession sqlSession = sqlSessionFactory.openSession(true);
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.selectById(1L);
Mybatis底层执行原理图
源码说明
1.加载配置
1.1. 当我们执行 sqlSessionFactoryBuilder.build 的时候,SQLSessionFactoryBuilder底层会加载Mybatis配置文件和解析Mapper.xml 映射文件。底层通过Resource以InputStream的方式加载资源文件,执行XmlConfigBuilder#parse进行配置文件的解析
1.2. XmlConfigBuilder#parse 方中会通过XPathParser解析Mybatis的配置文件,解析其中的配置,比如:properties,settings,typeAliases,plugins等等,这里重点说一下:environments和mappers
1.3. 对于environments而言主要是会得到:transactionManager事务管理器,和 DataSourceFactory 数据源,然后都会封装到 Environment,再设置给一个:Configuration 对象(Mybatis核心配置对象,里面维护了Mybatis各种核心组件,比如:别名,mapper, TypeHandler等等都会在里面)
1.4. 除此之外还会解析mappers映射文件通过 XmlMapperBuilder进行解析,解析好之后会得到:MapperRegistry(维护Mapper映射器生成jdk代理),TypeHandler(类型处理),MappedStatement(SQL语句的封装),ResultMap(结果映射),typeAliasRegistry(维护别名)等等。这些东西都会封装到Confuration对象中,并创建一个 DefaultSqlSessionFactory对象把Configuration交给该工厂
2.获取SqlSession
在执行DefaultSqlSessionFactory#openSession的时候,底层会创建好Executor执行器,并把执行器和Configuration设置给DefaultSqlSession对象,并发返回DefaultSqlSession
3.获取Mapper
当执行sqlSession.getMapper的时候,会从Configuration的MapperRegistry中根据Mapper的类型获取Mapper实例。底层会通过 MapperProxyFactory来创建Mapper,用到了JDK动态代理,MapperProxy中是增强逻辑。
4.执行Mapper
1.在执行Mapper方法的时候代码会来到 MapperProxy#invoke方法中,方法中会构建一个 MapperMethod去执行,会根据SQL的类型做不通的执行,比如:是select查询就会走SqlSession#selectOne,该方法底层使用的是SqlSession#selectList方法。
2.selectList方法中会调用executor.query去执行,方法中会找到对应的语句对象MappedStatement,参数:parameter,结果处理器ResultHandler等,executor有很多种,通过委派进行调用。
3.然后就是 通过Configuration创建一个 PreparedStatementHandler,通过该hander去创建一个PreparedStatement,并为其设置好参数,SQL也会把参数替换为 “?”。
4.然后就是调用PreparedStatementHandler#query去执行PreparedStatement,这里比较简单就是执行PreparedStatement#execute方法(JDBC的内容)。
5.接下来就是调用 ResultHandler#handleResultSets去处理执行的结果了,结果处理方案是从 PreparedStatement中拿到ResultSet,然后从ResultMap中拿到ResultType,调用:ObjectFactory#create方法根据ResultType创建结果对象的实例(反射)。再通过反射拿到对象的Field,拿到ResultSet中对应的值,通过反射给Field赋值,字段的类型会通过jdbcType来处理。
6.最后把结果对象转到List里面进行返回,如果是selectOne,就会取list中的第0个元素返回。
总结
相比Spring来说Mybatis的源码是相对简单的,你可以通过上面的源码去深入理解Mybatis核心机制,当然这里的源码只是实现了简单的单个对象查询,时间关系其中很多细节是没有去实现的,但是毫不影响你对Mybatis的理解或者用于面试吊打面试官了。建议你对着图多看几遍。