文章目录
获取mapper接口实例源码
// 5.获取对应的mapper
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 6.执行方法
UserEntity user = userMapper.getUser(1);
接口没有实例化怎么被调用的呢?使用jdk动态代理
jdk动态代理
- 略
伪代码实现动态获取mapper接口实现类
public class JdkMapperProxy implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args){
return new UserEntity(1L, "myx", 28);
}
}
public class TestMyBatisJdk {
public static void main(String[] args) {
// 代理模式 动态代理 不需要写代理类。 jdk和cglib mybatis jdk动态代理
// jdk动态代理实现原理
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// 接口如果没有实例化,如何被调用呢? 动态代理技术 走同一个invoke 方法
UserMapper mapper = getMapper(UserMapper.class);
UserEntity user = mapper.getUser(1);
System.out.println(user.getName());
}
private static <T> T getMapper(Class<T> type) {
//由于没有实现类只能写接口的类型
//没有实现类对象 new JdkMapperProxy()无参数即可
return (T) Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, new JdkMapperProxy());
}
}
UserMapper.xml如何被加载到内存
获取mapper代理源码
// 5.获取对应的mapper
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 6.执行方法
UserEntity user = userMapper.getUser(1);
由于MapperRegistry中存储MapperProxyFactory map的key是Class类型。
所以每执行一次sqlSession.getMapper()就会获取一个新的Mapper代理,但是我们平时开发过程中可能是通过spring管理bean所以只调用了一次获取Mapper代理方法。
mybatis基于多个不同接口生成代理类,不同接口肯定执行不同的invoke方法,相同接口,不同方法肯定走同一个invoke方法。
执行方法分析
最终只执行的为MapperProxy.invoke()
- org.apache.ibatis.binding.MapperProxy#invoke
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
//缓存提升速度
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
- org.apache.ibatis.binding.MapperMethod#execute
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
if (Sql