为什么sqlSession.getMapper()能够得到对象?
在mybatis开发的过程中,我们只是定义了接口,但是却可以调用接口的方法去完成功能,因为接口无法实例化,那么必然mybatis做了特殊处理。
mybatis通过getMapper()实际上生成了代理对象
首先是要了解代理对象使用的场景
1、无中生有 - 就是mybatis这种情况,没有对象,要根据接口生成对象
2、要为原始对象增加与主逻辑无关的功能,如事务、日志
3、远程代理 (RPC)
实现原理
实现原理非常简单,就是使用jdk的动态代理,动态字节码技术,在spring aop中也是同样的原理
// classLoader 类加载器
// interfaces 代理类要实现的接口
// invocation 额外功能
Proxy.newProxyInstance(classLoader, interfaces, invocation)
/**
classLoader作用 1、加载.class文件到JVM 2、根据.class文件创建对象
因为代理对象没有.class文件,又因为classLoader是与.class文件相关联的,所以代理对象是没有classLoader与其对应的。动态字节码技术就是直接把.class文件生成到JVM中。
所以此处的classLoader是可以借用任意类的加载器
**/
Mybatis源码
MapperProxyFactory 和 MapperProxy
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
// 实现InvocationHandler就是提供的额外功能
// 要提供的额外功能无非就是sql的执行,执行就需要sqlSession,namespace.id,执行的sql类型
// 最后要根据CURD类型,也就是sql标签中的类型,决定是sqlSession.select()|.update|.delete
public class MapperProxy<T> implements InvocationHandler, Serializable {
}
总结
1. sqlSession.getMapper(UserDAO.class);底层是通过动态字节码也就是动态代理得到的代理对象。
2. 代理对象执行sql底层是通过sqlSession来实现的。