我们先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. HDU 3726 Graph and Queries(平衡二叉树)(2010 Asia Tianjin Regional Contest)

    Description You are given an undirected graph with N vertexes and M edges. Every vertex in this grap ...

  2. POJ 3304 Segments(线的相交判断)

    Description Given n segments in the two dimensional space, write a program, which determines if ther ...

  3. js如何使浏览器允许脚本异步加载

    js如何使浏览器允许脚本异步加载 如果脚本体积很大,下载和执行的时间就会很长,因此造成浏览器堵塞,用户会感觉到浏览器“卡死”了,没有任何响应.这显然是很不好的体验,所以浏览器允许脚本异步加载,下面就是 ...

  4. PHP中通过preg_match_all函数获取页面信息并过滤变更为数组存储模式

    // 1. 初始化 $ch = curl_init(); // 2. 设置选项 curl_setopt($ch, CURLOPT_URL, "http://test.com/index.js ...

  5. NYOJ 35 表达式求值(逆波兰式求值)

    http://acm.nyist.net/JudgeOnline/problemset.php?typeid=4 NYOJ 35 表达式求值(逆波兰式求值) 逆波兰式式也称后缀表达式. 一般的表达式求 ...

  6. Ubuntu16.04修改IP

    首先用root用户登陆,然后输入你root的密码.如下图:   然后编辑interfaces文件,该文件位于/etc/network/下,执行如下命令: vim /etc/network/interf ...

  7. k邻近算法理解及代码实现

    github:代码实现 本文算法均使用python3实现 1 KNN   KNN(k-nearest neighbor, k近邻法),故名思议,是根据最近的 $ k $ 个邻居来判断未知点属于哪个类别 ...

  8. 关于命令行参数argv(《学习OpenCV》)

    在<学习OpenCV>这本书中,很多示例代码都用到了命令行参数.作为新手,之前总是很困扰,不知道怎么用.偶然的机会终于略知一二了. 在Visual Studio中,我们可以自行设置命令行参 ...

  9. 通过access_token openid获取微信用户昵称等信息

    <?php header('Access-Control-Allow-Origin:*'); $access_token = !empty($_GET['access_token'])?$_GE ...

  10. RabbitMQ安装与初始配置【转载】

    Erlang安装 rabbitmq依赖于Erlang,需先安装,推荐安装rabbitmq/erlang-rpm: #clone源码 git clone https://github.com/rabbi ...