通过分析MapperRegistry类的addMapper方法,可以看出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,创建一个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);
// 解析type的class name对于的所有的信息
parser.parse();
// 在末尾设一个标志位,用来判断程序是否执行到此处
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
从源码中我们可以看出该方法中的parser.parse();的方法是生成和初始化mapper的主要入口,下面是MapperAnnotationBuilder的parse方法:
public void parse() {
// type是mapper的class信息
String resource = type.toString();
if (!configuration.isResourceLoaded(resource)) {
// 1、解析mapper的xml配置文件信息
loadXmlResource();
configuration.addLoadedResource(resource);
// type.getName=xml文件中的mapper的namespace
assistant.setCurrentNamespace(type.getName());
// 2、解析mapper的cache注解
parseCache();
// 3、解析mapper中cache的引用
parseCacheRef();
// 4、解析mapper类型的所有的方法
Method[] methods = type.getMethods();
for (Method method : methods) {
try {
// issue #237
if (!method.isBridge()) {
// 解析mapper接口的方法的注解信息
parseStatement(method);
}
} catch (IncompleteElementException e) {
configuration.addIncompleteMethod(new MethodResolver(this, method));
}
}
}
parsePendingMethods();
}
从上面的代码我们可以看出mapper初始化的步骤,其中每一步的解析过程中的部分关键源码我已经用中文进行了注释Mybatis源码中文注解。
通过分析源码可以看出,如果同时在xml和mapper接口中对方法进行配置,那么接口中的注解配置会覆盖掉该方法在xml中配置。
当然在分析mapper的初始化源码的过程中,还有其他需要非常用价值的信息,后续将会继续跟进。
https://github.com/mh47838704/mybatis-3 mybatis源码中文注释版