动态代理 invoke 方法
问题
mapperProxy.findByCondition(1); 是怎么完成的增删改查操作?
当通过 JDK 代理方式生成代理对象后,可以通过代理对象执行代理方法
public class MybatisTest {
@Test
public void test2 ( ) throws IOException {
. . .
User user = mapperProxy. findByCondition ( 1 ) ;
. . .
}
}
因为 mapperProxy 是个代理对象,所以会执行 invoke() 方法。对于 Object 的方法会直接跳过代理,否则会使用 PlainMethodInvoker 执行代理调用逻辑,同时从这里还能看出 MapperProxy 是实现了 InvocationHandler 接口,所以可以
public class MapperProxy < T > implements InvocationHandler , Serializable {
private static final int ALLOWED_MODES = MethodHandles. Lookup . PRIVATE | MethodHandles. Lookup . PROTECTED
| MethodHandles. Lookup . PACKAGE | MethodHandles. Lookup . PUBLIC;
private final SqlSession sqlSession;
private final Class < T > mapperInterface;
private final Map < Method , MapperMethodInvoker > methodCache;
. . .
@Override
public Object invoke ( Object proxy, Method method, Object [ ] args) throws Throwable {
try {
if ( Object . class . equals ( method. getDeclaringClass ( ) ) ) {
return method. invoke ( this , args) ;
} else {
return cachedInvoker ( method) . invoke ( proxy, method, args, sqlSession) ;
}
} catch ( Throwable t) {
throw ExceptionUtil . unwrapThrowable ( t) ;
}
}
private MapperMethodInvoker cachedInvoker ( Method method) throws Throwable {
try {
return MapUtil . computeIfAbsent ( methodCache, method, m -> {
if ( m. isDefault ( ) ) {
. . .
} else {
return new PlainMethodInvoker ( new MapperMethod ( mapperInterface, method, sqlSession. getConfiguration ( ) ) ) ;
}
} ) ;
} catch ( RuntimeException re) {
Throwable cause = re. getCause ( ) ;
throw cause == null ? re : cause;
}
}
}
从上面代码 3 中看到,在执行 PlainMethodInvoker 的 invoke() 前,首先初始化构造 MapperMethod ,特别要注意创建 SqlCommand 对象,这个属性等等会用到
public class MapperMethod {
private final SqlCommand command;
private final MethodSignature method;
public MapperMethod ( Class < ? > mapperInterface, Method method, Configuration config) {
this . command = new SqlCommand ( config, mapperInterface, method) ;
this . method = new MethodSignature ( config, mapperInterface, method) ;
}
. . .
}
SqlCommand 创建会获取当前调用的方法,以及对应的接口名称,通过接口名称 + 方法名称的方式,就能拿到 MappedStatement ,从而得知 SqlCommand 的执行类型
public static class SqlCommand {
private final String name;
private final SqlCommandType type;
. . .
public SqlCommand ( Configuration configuration, Class < ? > mapperInterface, Method method) {
final String methodName = method. getName ( ) ;
final Class < ? > declaringClass = method. getDeclaringClass ( ) ;
MappedStatement ms = resolveMappedStatement ( mapperInterface, methodName, declaringClass,
configuration) ;
if ( ms == null ) {
if ( method. getAnnotation ( Flush . class ) != null ) {
name = null ;
type = SqlCommandType . FLUSH;
} else {
throw new BindingException ( "Invalid bound statement (not found): "
+ mapperInterface. getName ( ) + "." + methodName) ;
}
} else {
name = ms. getId ( ) ;
type = ms. getSqlCommandType ( ) ;
if ( type == SqlCommandType . UNKNOWN) {
throw new BindingException ( "Unknown execution method for: " + name) ;
}
}
}
}
完成初始化 MapperMethod 之后,就开始真正执行 PlainMethodInvoker 的 invoke() 方法,实际也是交由 MapperMethod 执行 execute() 方法
public class MapperProxy < T > implements InvocationHandler , Serializable {
. . .
private static class PlainMethodInvoker implements MapperMethodInvoker {
private final MapperMethod mapperMethod;
public PlainMethodInvoker ( MapperMethod mapperMethod) {
super ( ) ;
this . mapperMethod = mapperMethod;
}
@Override
public Object invoke ( Object proxy, Method method, Object [ ] args, SqlSession sqlSession) throws Throwable {
return mapperMethod. execute ( sqlSession, args) ;
}
}
}
在 MapperMethod 的 execute() 方法中,它会根据 SqlCommand 的方法类型,选择调用 SqlSession 的不同方法,对于 INSERT、UPDATE、DELETE 类型,其实最后都是执行 update 操作,SELECT 类型会根据方法返回的类型,执行不同的处理方法。根据我们的实验,最终是会执行查询单条 sqlSession.selectOne() 方法,并且会把结果返回
public class MapperMethod {
private final SqlCommand command;
private final MethodSignature method;
. . .
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;
}
}
总结