MyBatis的解析和运行原理
- 了解MyBatis解析配置文件的大致过程
- 掌握MyBatis底层映射保存的数据结构(MappedStatement,SqlSource,BoundSql)及其内容
- 了解MyBatis Mapper的运行原理
- 掌握SqlSession运行原理
- 掌握SqlSession下四大对象的设计原理和具体方法的作用
MyBatis的运行过程分为两大步:第1步,读取配置文件缓存到Configuration对象,用以
创建SqlSessionFactory;第2步,SqlSession的执行过程。
构建SqlSessionFactory过程
最重要的功能是提供MyBatis的核心接口SqlSession
采用Builder模式去创建SqlSessionFactory,在实际中可以通过SqlSessionFactoryBuilder去构建,其构建分为两步:
- 通过 org.apache.ibatis.builder.xml.XMLConfigBuilder 解析配置的 XML 文件,
读出所配置的参数,并将读取的内容存入 org.apache.ibatis.session.Configuration 类对象中。而Configuration 采用的是单例模式,几乎所有 MyBatis 配置内容都会存放在这个单例对象中,以便后续将这些内容读出。 - 使用 Configuration 对象去创建 SqlSessionFactory。MyBatis中的SqlSessionFactory
是一个接口,而不是一个实现类,为此 MyBatis 提供了一个默认的实现类
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory 。在大部分情况下都没有必要自己去创建新 SqlSessionFactory 实现类。
构建Configuration
Configuration是提供XMLConfigBuilder去构建的,首先读出所以的XML配置的信息,然后把它们解析并保存在Configuration单例中。
构建映射器的内部组成
一般而言,在MyBatis中一条SQL与它相关的配置是由3个部分组成的,它们分别是MappedStatement,
SqlSource和BoundSql。
- MappedStatement作用是保存一个映射器节点(select | insert | delete | update)的内容。它还有一个重要的属性sqlSource。MyBatis通过读取它来获得某条SQL配置的所有信息。
- SqlSource是提供BoundSql对象的地方,它是MappedStatement的一个属性。
他的作用是根据上下文和参数解析生成需要的SQL。 - BoundSql是一个结果对象,也就是SqlSource通过对SQL和参数的联合解析得到的SQL和参数,它是建立SQL和参数的地方。主要会提供三个属性:parameterMappings、parameterObject和sql。
- parameterObject为参数本身,可以传递简单对象,POJO或者Map,@Param
注解的参数。 - parameterMappings是一个List,他的每个元素都是ParameterMapping对象。对象会描述参数,参数包括属性名称、表达式、javaType、jdbcType、typeHandler等重要信息。
- sql属性就是书写在映射器里面的一条被SqlSource解析后的SQL。
- parameterObject为参数本身,可以传递简单对象,POJO或者Map,@Param
构建SqlSessionFactory
SqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession运行过程
映射器(Mapper)的动态代理
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class)
MyBatis源码是如何实现getMapper方法的:
public <T> T getMapper(Class<T> type) {
return this.configuration.getMapper(type, this);
}
显然运用到了Configuration对象的getMapper方法,追踪这个方法:
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}
运用了映射器的注册器MapperRegistry来获取对应的接口对象,如下:
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);
}
}
}
首先判断是否注册一个Mapper,如果没有则会抛出异常;如果有,就会启用MapperProxyFactory