前面两篇博客​​Mybatis接口编程原理分析(一)​​​和​​Mybatis接口编程原理分析(二)​​我们介绍了MapperProxyFactory、MapperProxy和MapperMethod的操作及源码分析,接下来我们介绍MapperRegistry

MapperRegistry:它是用来注册Mapper接口和获取登出代理类实例的工具类,它通过getMapper函数获得代理类和addMapper函数来注册代理类,

源码如下:

 

//这个类通过名字就可以看出 是用来注册Mapper接口与获取生成代理类实例的工具类
public class MapperRegistry {

//全局配置文件对象
private final Configuration config;

//一个HashMap Key是mapper的类型对象, Value是MapperProxyFactory对象
//这个MapperProxyFactory是创建Mapper代理对象的工厂
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) {
//通过Mapper的接口类型 去Map当中查找 如果为空就抛异常
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
//否则创建一个当前接口的代理对象 并且传入sqlSession
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);
}
//注册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 {
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
*/
//注册Mapper接口
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.xml时会根据namespace来加载对应的接口类

private void bindMapperForNamespace() {
//获取namespace
String namespace = this.builderAssistant.getCurrentNamespace();
if (namespace != null) {
Class boundType = null;

try {
//判断namespace是否是一个接口
boundType = Resources.classForName(namespace);
} catch (ClassNotFoundException var4) {
;
}

//如果存在接口类在调用addMapper
if (boundType != null && !this.configuration.hasMapper(boundType)) {
this.configuration.addLoadedResource("namespace:" + namespace);
this.configuration.addMapper(boundType);
}
}

}

在DefaultSqlSession中通过getMapper函数从Configuration中获取代理类:

 

 

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

 

 

在Configuration类中通过getMapper从MapperRegistry来获取代理类

 

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

这样就完成了mybatis接口编程的构造和调用的全部过程。