原理
MyBatis的运行过程分为两大步:
- 读取配置文件缓存到Configuration对象中,用于创建SqlSessionFactory
- SqlSession的执行过程
构建SqlSessionFactory过程
- 通过 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的实现类,这种创建方式就是一种Builder模式。
XMLConfigBuilder中解析XML方法源码:
public class XMLConfigBuilder extends BaseBuilder {
......................
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
try {
propertiesElement(root.evalNode("properties")); //issue #117 read properties first
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
settingsElement(root.evalNode("settings"));
environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
............................
}
我们可以看到它是通过一个一个节点的解析XML的内容得到对应的信息,最后构建出一个Configuration对象。
有了Configuration对象,就可以通过SqlSessionFactoryBuilder的build方法构建SqlSessionFactory对象
public class SqlSessionFactoryBuilder {
...................
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
.......................
}
SqlSession执行过程
有了SqlSessionFactory对象就可以轻易的获取SqlSession,SqlSession也是个接口,给出了查询、插入、更新、删除的方法。
public class DefaultSqlSessionFactory implements SqlSessionFactory {
..................
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
..................
}
Mapper的动态代理
SqlSession中提供了一个getMapper方法,例如:
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
源码:
public class DefaultSqlSession implements SqlSession {
............................
public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}
............................
}
public class Configuration {
................
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
.................
}
public class MapperRegistry {
private Configuration config;
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
public MapperRegistry(Configuration config) {
this.config = config;
}
@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null)
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
...........................................
}
可以很明显的看出,它运用到了Configuration对象的getMapper方法获取对应的接口对象,又运用了映射器的注册器Mapperregistry获取对应的接口对象。首先会判断是否注册一个Mapper,如果没有则抛出异常信息,如果有就会启用MapperProxyFactory工厂生成一个代理实例。
SqlSession的四大对象
- Executor代表执行器,由它调度StatementHandler、ParameterHandler、ResultSetHandler等来执行对应的SQL,其中StatementHandler是最重要的。
- StatementHandler的作用是使用数据库的Statement(PreparedStatement)执行操作,它是四大对象的核心,起到承上启下的作用,许多插件都是通过拦截它来实现的。
- ParameterHandler是用来处理SQL参数的。
- ResultSetHandler是进行数据集(ResultSet)的封装返回处理的,不经常使用。