提问
大家都知道,mybatis通过接口类定义增删改查方法,然后有个一一映射的mapper文件,在执行sql时,没有接口的实现类,却依然可以执行增删改查,这是为什么呢?
解读
首先,要解释这个问题,要知道jdk有个Proxy的类,可以生成代理对象,可能有的人会问,Proxy代理不也的有个实现类吗?这个地方要郑重说明一下,Proxy是接口代理,可以没有接口实现,我们平时看到的有实现类,仅仅是因为我们在代理类的处理InvocationHandler实现类中要调用实现类的方法罢了,比如
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//return method.invoke(object, args);
System.out.println("哈哈,你被骗啦");
return null;
}
我们常见的写法是上面注释的这种,但是mybatis的增删改成是通过执行对象来处理的,不是通过和接口的方法的实现来处理的,这就说明了在invoke中,我们不需要一个实现类,也不需要对应的实现方法,就好像上面打印的语句一样。
那mybatis是如何实现代理以及增删改查的,主要是以下方法:
1、在初始化的时候生成对应mapper的信息
2、通过MapperProxyFactory类来生成对应接口的代理对象,代理对象执行的处理器是MapperProxy。
3、在MapperProxy的invoke中执行对应的增删改成操作,对应的源代码如下:
@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 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这一步,大家应该就容易理解了,就好像没有使用接口,而直接使用sqlsession去执行sql一样了