在上一篇文章Mybatis:Mapper接口编程原理分析(三)中,已经获取到了 mapper 接口的代理,而且也知道它使用的 JDK 动态代理。而实现 InvocationHandler 接口的类是 MapperProxy,因此接下来分析 MapperProxy。还是老规矩,通过查看它的源码。
- MapperProxy
public class MapperProxy<T> implements InvocationHandler {
private final SqlSession sqlSession;
// 被代理接口的类型对象
private final Class<T> mapperInterface;
// 被代理接口中方法的缓存,由MapperProxyFactory传递过来
private final Map<Method, MapperMethod> methodCache;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
// 所有被代理接口的方法被此方法拦截
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// 在 Object 类中声明的方法不需要额外处理。如 hashCode 、toString
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
// java8 支持在接口中定义 default 方法
if (this.isDefaultMethod(method)) {
return this.invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
// 对方法进行缓存
MapperMethod mapperMethod = this.cachedMapperMethod(method);
// 核心的地方就在这,此时才是真正对 SqlSession 进行的包装调用
return mapperMethod.execute(this.sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = (MapperMethod)this.methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
this.methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
@UsesJava7
private Object invokeDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable {
Constructor<Lookup> constructor = Lookup.class.getDeclaredConstructor(Class.class, Integer.TYPE);
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
Class<?> declaringClass = method.getDeclaringClass();
return ((Lookup)constructor.newInstance(declaringClass, Integer.valueOf(15))).unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
}
private boolean isDefaultMethod(Method method) {
return (method.getModifiers() & 1033) == 1 && method.getDeclaringClass().isInterface();
}
}
网友评论