Mybatis Mapper 接口工作原理 3 - mapper 代理对象执行
当调用 Mapper 接口的方法时,实际上调用的是代理对象的方法。由于代理对象是通过 JDK 动态代理生成的,因此方法调用会被转发给 InvocationHandler 的 invoke 方法。
1 MapperProxy.invoke() 的源码分析
MapperProxy 是 InvocationHandler 的实现类,invoke 方法的实现如下:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 如果是 Object 类的方法(如 toString、hashCode),直接调用
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
// 获取 MapperMethod 并执行
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
cachedMapperMethod(method):缓存MapperMethod对象,避免重复创建。mapperMethod.execute(sqlSession, args):调用MapperMethod的execute方法执行 SQL 查询。
2. 获取 MapperMethod
private MapperMethod cachedMapperMethod(Method method) {
// 从 Mapper 接口的方法中缓存该方法的解析结果
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(method, configuration);
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
public MapperMethod(Method method, Configuration configuration) {
// 获取方法的映射信息
this.configuration = configuration;
this.method = method;
// 获取方法上的注解或 XML 配置,进行解析
this.sqlCommand = getSqlCommand();
this.parameterType = getParameterType();
this.resultType = getResultType();
this.mapperMethodInvoker = buildMethodInvoker();
}
3. MapperMethod.execute() 的源码分析
MapperMethod 封装了 Mapper 接口方法的执行逻辑,execute 方法的实现如下:
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT:
result = sqlSession.insert(command.getName(), args);
break;
case UPDATE:
result = sqlSession.update(command.getName(), args);
break;
case DELETE:
result = sqlSession.delete(command.getName(), args);
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 {
result = executeForOne(sqlSession, args);
}
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
return result;
}
4. 总结
1. sqlSession.getMapper() 获取到的是什么?
获取到的是 Mapper 接口的代理对象,这个代理对象是通过 JDK 动态代理生成的,核心类是 MapperProxy。
2. 调用 mapper 方法执行原理
- 因为 mapper 实际的对象是 JDK 动态代理生成的,所以调用 mapper 的方法会被拦截,会触发
MapperPoxy.invoke()方法 MapperPoxy.invoke()中会调用MapperMethod.execute()方法(被调用的方法会被封装成MapperMethod对象)MapperMethod.execute()会调用SqlSession的方法SqlSession的工作原理请看 这里

浙公网安备 33010602011771号