前沿:在MyBatis源码解析(三):初始化SqlSession博客中,已经对 openSession() 底层进行解析,并获取到 SqlSession 对象;接着,需要通过 SqlSession.getMapper(),获取 Mapper 的代理对象去执行 Statement,getMapper()分析会与之前已经分析过的addMapper() 相比较进行分析,以确保流程清晰,具体 addMapper() 流程可参考MyBatis源码解析(二):初始化SqlSessionFactory
一,初始化 Mapper 流程图
1,流程图
2,流程解析
* 在 SqlSessionFactory 解析中,MyBatis会将配置文件解析到的 Mapper 文件添加到 Configuration对象中,Configuration对调用 MapperRegistery 对象保存 Mapper 实例其内部一 Map 容器中;
* getMapper()时,会根据上一步 addMapper(),相同方式走一遍 getMapper()流程,并最终通过JDK动态代理初始化代理对象
二,初始化步骤
1,获取 Mapper 实例
* 通过 DefaultSqlSession 来 getMapper()
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
* DefaultSqlSession 从 Configuration 中 getMapper()
@Override
public <T> T getMapper(Class<T> type) {
// 触发Mapper获取, 从Configuration配置对象中获取Mapper
// 在初始化配置信息时, Configuration.addMapper会调用MapperRegistery存储Mapper到Map容器中
// 存储过程可以参考前一篇博客, 初始化SqlSessionFactory
return configuration.<T>getMapper(type, this);
}
* Configuration 从 MapperRegistery 中 getMapper()
-- 初始化 SqlSessionFactory 时, 通过调用 addMapper() 已经存储 Mapper 到 MapperRegistery 中
public <T> void addMapper(Class<T> type) {
// 存储时调用MapperRegistry存储
mapperRegistry.addMapper(type);
}
-- getMapper() 时,同样根据 MapperRegistery 进行获取
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// 获取时同样调用MapperRegistry进行获取
return mapperRegistry.getMapper(type, sqlSession);
}
* MapperRegistery 根据传递的 Mapper 类型从 Map 容器中获取已经初始化的 MapperProxyFactory 对象
-- 初始化 SqlSessionFactory 时,已经添加 Mapper 映射到 Map容器中,并初始化 MapperProxyFactory 传递了 Mapper 类型
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
// 添加Mapper将Mapper添加到Map容器中, 并初始化value为MapperProxyFactory
// 此时MapperProxyFactory初始化已经传递Mapper类型到工厂类中
knownMappers.put(type, new MapperProxyFactory<T>(type));
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the
// mapper parser. If the type is already known, it won't try.
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
-- getMapper()时,直接从 MapperRegistery 的 Map容器中根据类型,获取 Mapper 的对应 MapperProxyFactory 对象,并进行初始化
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// 从Map容器中获取该对象, 获取初始化的MapperProxyFactory
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
// 从MapperProxyFactory中实例化一个Mapper代理对象
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
2,通过JDK动态代理初始化代理对象
* 从上一步获取的 MapperProxyFactory 中初始化实例
public T newInstance(SqlSession sqlSession) {
// 初始化MapperProxy, 该类为InvocationHandler实现类, 动态代理最终执行该类的Invoke方法
// mapperInterface 在初始化传递过程中已经初始化为当前Mapper类型
// methodCache可以理解为statement缓存容器, 实例为ConcurrentHashMap
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
* 调用JDK动态代理最终生成 Mapper 代理对象并返回
protected T newInstance(MapperProxy<T> mapperProxy) {
// 通过JDK动态代理方式, 生成Mapper的代理对象,
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}