本文将根据下面这段代码进行源码分析
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<UserEntity> list = mapper.listUser();
System.out.println(list);
sqlSession.close();
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
ClassLoaderWrapper.java
从入口一路点击进去可以发现底层是通过调用java.lang.ClassLoader#getResourceAsStream方法来读取resources目录下的mybatis-config.xml文件,并得到InputStream对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactoryBuilder.java
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
XMLConfigBuilder.java
XPathParser.java
可以发现底层是将InputStream对象转换成Document对象,并将Document对象保存至当前类(XPathParser)的document属性中
继续回到上一层,点击进入this()方法
XMLConfigBuilder.java
可以发现this()方法主要是在进行部分属性的初始化,并将XPathParser对象保存至当前类(XMLConfigBuilder)的parser属性中。
关键点:初始化了父类的configuration属性。
return build(parser.parse());
XMLConfigBuilder.java
XPathParser.java
XMLConfigBuilder.java
XMLConfigBuilder.java
点击进入addMappers(mapperPackage)方法
Configuration.java
MapperRegistry.java
从这里可以发现parser.parse()主要是在解析配置文件(mybatis-config.xml),具体过程是根据Document对象获取节点为configuration的配置信息,并转换成XNode对象再解析各个节点,重点部分是mappers节点的解析。
在解析mappers节点的代码中可以发现如果是使用package或class注册mapper可以直接注册mapper接口对象,如果是使用url或者resource注册mapper则需要先解析mapper.xml映射文件后并通过namespace找到所绑定的接口对象再进行注册。
mapper的注册是通过MapperRegistry对象完成的,而MapperRegistry则是Configuration对象里面的一个属性,也就是说所有的配置解析完成后都存放在Configuration对象中。
parser.parse()最终返回Configuration对象。
SqlSessionFactoryBuilder.java
DefaultSqlSessionFactory.java
从这里可以发现SqlSessionFactoryBuilder将得到的Configuration对象建造成DefaultSqlSessionFactory对象,也就是SqlSessionFactory对象。
SqlSessionFactoryBuilder先是通过XMLConfigBuilder解析配置文件并将解析得到的配置装载到Configuration对象中,再将Configuration建造成DefaultSqlSessionFactory对象。
这里采用了建造者设计模式
BaseBuilder:所有解析器的父类,包含配置文件实例,为解析文件提供一些通用的方法;
XMLConfigBuilder:主要负责解析mybatis-config.xml文件;
XMLMapperBuilder:主要负责解析mapper.xml文件;
XMLStatementBuilder:主要负责解析映射文件中的SQL节点;
Configuration对象核心属性释义:
SqlSession sqlSession = sqlSessionFactory.openSession();
DefaultSqlSessionFactory.java
Configuration.java
从这里可以看到如果没有设置执行器类型,则会默认使用简单执行器类型
ExecutorType.java
上面枚举类中的三种执行器类型均可通过openSession()传参设置
点击进入openSessionFromDataSource()方法
DefaultSqlSessionFactory.java
openSessionFromDataSource()方法有三个入参:ExecutorType execType(执行器类型)、TransactionIsolationLevel level(事务隔离级别)、boolean autoCommit(是否自动提交)
DefaultSqlSessionFactory.java
TransactionFactory有两种:JdbcTransactionFactory,ManagedTransactionFactory
通过mybatis-config.xml文件进行配置
<transactionManager type="JDBC"/>
这里配置的是JdbcTransactionFactory
JdbcTransactionFactory.java
JdbcTransaction.java
Configuration.java
CachingExecutor.java
Mybatis默认使用的执行器是SimpleExecutor,SimpleExecutor的父类是BaseExecutor,BaseExecutor下一共有三个子类也就是三种执行器:BatchExecutor、SimpleExecutor、ReuseExecutor,这三种执行器均可通过传值设置。
cacheEnabled默认值为true,说明Mybatis默认会使用CachingExecutor。进入CachingExecutor类可以发现,CachingExecutor是在上面三种执行器(BaseExecutor)的基础上做了一层包装(装饰器设计模式),先调用CachingExecutor再调用BaseExecutor,是对BaseExecutor类的增强。
cacheEnabled可以通过mybatis-config.xml文件进行配置
<settings>
<setting name="cacheEnabled" value="false"/>
settings>
BaseExecutor是一级缓存(默认开启),默认使用SimpleExecutor,CachingExecutor是二级缓存(默认开启,但还需要做一些额外的配置才能生效)
将Configuration、Executor、autoCommit等信息包装成DefaultSqlSession对象,并且返回该对象
openSession()是SqlSessionFactory接口中的一个重载方法,可以配置执行器类型、事务隔离级别、是否自动提交等参数,Configuration负责判断当前使用的执行器(Executor),DefaultSqlSessionFactory最后将Configuration、Executor、autoCommit等信息包装成DefaultSqlSession对象并返回。
这里采用了装饰器设计模式
BaseExecutor是一级缓存(默认开启),BaseExecutor是BatchExecutor、SimpleExecutor、ReuseExecutor三种执行器的父类。
CachingExecutor是二级缓存(默认开启,但还需要做一些额外的配置才能生效)
CachingExecutor:可缓存数据的Executor,用装饰器模式包装了其它的执行器(如BaseExecutor下的三种执行器)
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
DefaultSqlSession.java
Configuration.java
MapperRegistry.java
之前已经对mapper接口进行了注册,这里通过mapper接口类型获取对应的动态代理工厂类(MapperProxyFactory),动态代理工厂类使用JDK动态代理技术生成mapper代理对象并返回该对象。
MapperProxyFactory.java
MapperProxy.java
JDK动态代理技术主要用于拦截和修改方法的调用,在使用mapper代理对象调用mapper接口中的方法时MapperProxy中的invoke方法也会被执行。
根据mapper接口类型从MapperRegistry中获取对应的动态代理工厂类(MapperProxyFactory),动态代理工厂类使用JDK动态代理技术生成mapper代理对象并返回该对象。在使用mapper代理对象调用方法时底层会走MapperProxy中的invoke方法。
这里采用了JDK动态代理设计模式
MapperRegistry:mapper接口动态代理工厂类的注册中心;
MapperProxyFactory:用于生成动态代理的实例对象;
MapperProxy:动态代理回调类;
List<UserEntity> list = mapper.listUser();
MapperProxy.java
核心代码
mapperMethod.execute(sqlSession, args);
MapperMethod.java
因为执行的SQL为select,返回值类型为List集合,所以会走executeForMany()方法
DefaultSqlSession.java
这个方法是不是很熟悉,没错,这就是在基于XML方式-原生方式开发用到的方法
List<UserEntity> list = sqlSession.selectList("com.mybatis.mapper.UserMapper.listUser", UserEntity.class);
DefaultSqlSession.java
如果开启了二级缓存则会使用CachingExecutor
CachingExecutor.java
SimpleExecutor中没有query方法,默认走父类(BaseExecutor)
BaseExecutor.java
SimpleExecutor.java
Configuration.java
RoutingStatementHandler.java
SimpleExecutor.java
2.1. 获取Connection
BaseExecutor.java
JdbcTransaction.java
2.2. 根据不同的StatementHandler创建Statement对象
RoutingStatementHandler.java
BaseStatementHandler.java
Mybatis默认采用PreparedStatementHandler处理器
PreparedStatementHandler.java
2.3. 使用ParameterHandler处理占位符参数
RoutingStatementHandler.java
PreparedStatementHandler.java
DefaultParameterHandler.java
RoutingStatementHandler.java
PreparedStatementHandler.java
DefaultResultSetHandler.java
在使用代理对象调用方法时,底层会走MapperProxy中的invoke方法,在执行查询语句时,默认会先从二级缓存(CachingExecutor)中读取数据,如果存在则直接返回,不存在则继续查询一级缓存,如果一级缓存(BaseExecutor)中存在则直接返回,不存在则继续查询数据库,在查询数据库时,总体上使用StatementHandler对象和JDBC进行交互,整个查询流程先是使用ParameterHandler对SQL语句的入参进行处理,待SQL语句被执行完后得到结果集,再使用ResultSetHandler对结果集进行处理并返回。
四大核心接口对象
StatementHandler