在上一篇 Mybatis:Mapper接口編程原理分析(一)中炕横,Mapper 接口最后向MapperRegistry 注冊。MapperRegistry 它是用來注冊 Mapper 接口和獲取 Mapper 接口代理類實(shí)例的工具類,完成這兩個工作是通過 getMapper 方法和 addMapper 方法。
它的源碼如下:
//注冊Mapper接口與獲取生成代理類實(shí)例的工具類
public class MapperRegistry {
//全局配置文件對象
private final Configuration config;
//一個HashMap Key是mapper的類型對象, Value是MapperProxyFactory對象
//這個MapperProxyFactory是創(chuàng)建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當(dāng)中查找 如果為空就拋異常
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
//否則創(chuàng)建一個當(dāng)前接口的代理對象 并且傳入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 接口只會被加載一次粗井,然后緩存在 HashMap 中唧取,其中 key 是 mapper 接口類對象航夺,value 是 mapper 接口對應(yīng)的 代理工廠。需注意的是腥光,每個 mapper 接口對應(yīng)一個代理工廠关顷。