我们先Mapper接口的调用方式,见<MyBatis框架中Mapper映射配置的使用及原理解析(一) 配置与使用>的示例:

public void findUserById() {
SqlSessionFactory sqlSessionFactory = getSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.selectByPrimaryKey(1l);
System.out.println(user.getId() + " / " + user.getName());
}

sqlsession.getMapper(UserMapper.class)  也就是调用DefaultSqlSession的对应方法:

  public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}

继续跟踪Configuration对象对应源码:

 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}

我们在回忆,在 <MyBatis框架中Mapper映射配置的使用及原理解析(四) 解析Mapper接口映射xml文件> 一文,我们知道在读取mapper xml文件后会调用org.apache.ibatis.builder.xml.XMLMapperBuilder类的bindMapperForNamespace()方法,绑定到命名空间:

private void bindMapperForNamespace() {
String namespace = builderAssistant.getCurrentNamespace();
if (namespace != null) {
Class<?> boundType = null;
try {
boundType = Resources.classForName(namespace);
} catch (ClassNotFoundException e) {
//ignore, bound type is not required
}
if (boundType != null) {
if (!configuration.hasMapper(boundType)) {//判断是否存在
// Spring may not know the real resource name so we set a flag
// to prevent loading again this resource from the mapper interface
// look at MapperAnnotationBuilder#loadXmlResource
configuration.addLoadedResource("namespace:" + namespace);//添加资源标识
configuration.addMapper(boundType); //Mapper接口添加到Configuration
}
}
}
}
继续跟踪configuration.addMapper(boundType)方法:
  public <T> void addMapper(Class<T> type) {
mapperRegistry.addMapper(type);
}

我们发现添加和获取Mapper实例都使用到了同一个类MapperRegistry,在Configuration中的声明如下:

protected MapperRegistry mapperRegistry = new MapperRegistry(this);

下面贴出MapperRegistry的源代码:

package org.apache.ibatis.binding;

import org.apache.ibatis.builder.annotation.MapperAnnotationBuilder;
import org.apache.ibatis.io.ResolverUtil;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession; import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set; 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);
}
} public <T> boolean hasMapper(Class<T> type) {
return knownMappers.containsKey(type);
} 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 {
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);
}
}
}
} /**
* @since 3.2.2
*/
public Collection<Class<?>> getMappers() {
return Collections.unmodifiableCollection(knownMappers.keySet());
} /**
* @since 3.2.2
*/
public void addMappers(String packageName, Class<?> superType) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
for (Class<?> mapperClass : mapperSet) {
addMapper(mapperClass);
}
} /**
* @since 3.2.2
*/
public void addMappers(String packageName) {
addMappers(packageName, Object.class);
} }

我们清楚的看到注册Mapper和获取Mapper都是在一个Map对象中存取Mapper的代理对象MapperProxyFactory。

经过这篇文章,我们清楚的知道了MapperRegistry的功能就是注册和获取Mapper对象的代理。

MyBatis框架的使用及源码分析(六) MapperRegistry的更多相关文章

  1. MyBatis框架的使用及源码分析(十一) StatementHandler

    我们回忆一下<MyBatis框架的使用及源码分析(十) CacheExecutor,SimpleExecutor,BatchExecutor ,ReuseExecutor> , 这4个Ex ...

  2. MyBatis框架的使用及源码分析(九) Executor

    从<MyBatis框架的使用及源码分析(八) MapperMethod>文中我们知道执行Mapper的每一个接口方法,最后调用的是MapperMethod.execute方法.而当执行Ma ...

  3. MyBatis框架的使用及源码分析(八) MapperMethod

    从 <MyBatis框架中Mapper映射配置的使用及原理解析(七) MapperProxy,MapperProxyFactory> 文中,我们知道Mapper,通过MapperProxy ...

  4. MyBatis框架的使用及源码分析(五) DefaultSqlSessionFactory和DefaultSqlSession

    我们回顾<MyBatis框架中Mapper映射配置的使用及原理解析(一) 配置与使用> 一文的示例 private static SqlSessionFactory getSessionF ...

  5. MyBatis框架的使用及源码分析(四) 解析Mapper接口映射xml文件

    在<MyBatis框架中Mapper映射配置的使用及原理解析(二) 配置篇 SqlSessionFactoryBuilder,XMLConfigBuilder> 一文中,我们知道mybat ...

  6. MyBatis框架的使用及源码分析(二) 配置篇 SqlSessionFactoryBuilder,XMLConfigBuilder

    在 <MyBatis框架中Mapper映射配置的使用及原理解析(一) 配置与使用> 的demo中看到了SessionFactory的创建过程: SqlSessionFactory sess ...

  7. MyBatis框架的使用及源码分析(十) CacheExecutor,SimpleExecutor,BatchExecutor ,ReuseExecutor

    Executor分成两大类,一类是CacheExecutor,另一类是普通Executor. 普通类又分为: ExecutorType.SIMPLE: 这个执行器类型不做特殊的事情.它为每个语句的执行 ...

  8. MyBatis框架的使用及源码分析(七) MapperProxy,MapperProxyFactory

    从上文<MyBatis框架中Mapper映射配置的使用及原理解析(六) MapperRegistry> 中我们知道DefaultSqlSession的getMapper方法,最后是通过Ma ...

  9. MyBatis框架的使用及源码分析(三) 配置篇 Configuration

    从上文<MyBatis框架中Mapper映射配置的使用及原理解析(二) 配置篇 SqlSessionFactoryBuilder,XMLConfigBuilder> 我们知道XMLConf ...

随机推荐

  1. Thunder团队贡献分分配规则

    规则1:基础分,拿出总分的40%进行均分. 规则2:参与会议者,每人次加0.5分. 规则3:积极贡献者,通过团队投票,半数及以上同意,每次加0.5分. 规则4:根据项目完成情况,核实每个人的工作量,投 ...

  2. 对编码内容多次UrlDecode

    对编码内容多次UrlDecode,并不会影响最终结果. 尝试阅读了微软的源代码,不过不容易读懂. 网址:https://referencesource.microsoft.com/#System/ne ...

  3. OSG配置捷径,VS2013+WIN10

    在自己电脑上用CMAKE已经编译好了,上传到百度云里面了. 环境是WIN10+VS2013. 链接:http://pan.baidu.com/s/1hrO7GFE 密码:fwkw 解压之后放在C盘或者 ...

  4. 移动端调试和fiddler移动端抓包使用

    这里介绍一款移动端的调试工具以及抓包工具fiddler的使用.也是初次接触,算是初次接触的总结. 1,移动端调试工具.手机截图如下 代码实现 <!DOCTYPE html> <htm ...

  5. java 基础 --int 和Integer的区别

    感到脸红:int是整形 -128~127 Integer是正整型,你怎么会想到这样的回答,妈的,有脑子吗?!!! 1,int是基本数据类型,初始为0,Integer为封装类,初始为null ①无论如何 ...

  6. 【C/C++语法外功】类的静态成员理解

    例1  孙鑫視頻學習  Oct.27th 2009  Skyseraph 例子1.0 #include "iostream" class Point { public: void ...

  7. Delphi Dataset CurValue

    TField.CurValue Property Represents the current value of the field component including changes made ...

  8. Xcode开发技巧之code snippets(代码片段)

    一.什么是代码片段 当在Xcode中输入dowhile并回车后,Xcode会出现下图所示的提示代码: 这就是代码片段,目的是使程序员以最快的速度输入常用的代码片段,提高编程效率.该功能是从Xcode4 ...

  9. bzoj2676 Contra

    题意: 给定N,R,Q,S 有N个关卡,初始有Q条命,且任意时刻最多只能有Q条命 每通过一个关卡,会得到u分和1条命,其中u=min(最近一次连续通过的关数,R) 若没有通过这个关卡,将失去一条命,并 ...

  10. CentOS 文件及目录等

    1.在linux中一切皆是文件,只是类型不同,通过ls -l看到的一个字母表示文件的类型 -:普通文件. d:目录文件. l:链接文件. b:块设备文件. c:字符设备文件. p:管道文件. 2.文件 ...