Configuration:存储数据源,事务配置等信息
调用addMapper方法的时候它主要是调用的mapperRegistry的addMapper方法,
mapperRegistry会new一个MapperProxyFactory对象(构造函数的入参是我们的Mapper接口)
然后以Mapper接口的全限定名为key,MapperProxyFactory对象为值存放在Configuration内部的一个map对象中(knownMappers)
接下来就是调用MapperAnnotationBuilder的parse方法解析对应的xml文件或者是使用了注解的Mapper接口
public void parse() {
String resource = type.toString();
if (!configuration.isResourceLoaded(resource)) {
//判断是否有xml文件,如果有的话,使用对应的xml解析器进行解析
loadXmlResource();
configuration.addLoadedResource(resource);
//设置命名空间
assistant.setCurrentNamespace(type.getName());
//对CacheNamespace注解进行解析
parseCache();
//对CacheNamespaceRef注解进行解析
parseCacheRef();
//接下来是重点,对Mapper接口中的方法进行解析
Method[] methods = type.getMethods();
for (Method method : methods) {
try {
// issue #237
if (!method.isBridge()) {
//主要的解析方法,将解析出来的结果加到MappedStatement(assiant的属性)中
//生成MappedStatement的id值,解析对应的方法(增删改查),ResultMap,ParameterType,以及主键自增相关
parseStatement(method);
}
} catch (IncompleteElementException e) {
//解析失败的时候会先放在Configuration中一个LinkedList中(名字incompleteMethods)
configuration.addIncompleteMethod(new MethodResolver(this, method));
}
}
}
//对刚才解析失败的方法再进行一次解析
parsePendingMethods();
}
当获取接口对象的时候是DefultSqlSession的getMapper方法,其实主要是通过Configuration调用MapperRegistry的getMapper方法,如下:
public T getMapper(Class type, SqlSession sqlSession) {
//knowsMapper中通过接口的全限定名找到对应的MapperProxyFactory实体类
final MapperProxyFactory mapperProxyFactory = (MapperProxyFactory) 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);
}
}
下面是MapperProxyFactory的newInstance方法(可以看到主要就是使用了JDK动态代理帮我们生成了对应接口类的代理对象)
protected T newInstance(MapperProxy mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
那我们就知道了,调用对应的方法实质上就是调用MapperProxy的invoke方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (method.isDefault()) {
if (privateLookupInMethod == null) {
return invokeDefaultMethodJava8(proxy, method, args);
} else {
return invokeDefaultMethodJava9(proxy, method, args);
}
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
//缓存接口方法
final MapperMethod mapperMethod = cachedMapperMethod(method);
//最终的调用逻辑
return mapperMethod.execute(sqlSession, args);
}
//MapperMethod的execute方法
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional()
&& (result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}