type interface is not known to(聊聊Mybatis的binding模块)

首页教程更新时间:2023-05-15 11:50:52
聊聊Mybatis的binding模块

为什么我们在使用Mybatis的时候只需要写接口和xml文件就能执行sql呢?这就是Mybatis的binding模块需要做的事情了,今天我们分析一下Mybatis的binding模块,binding包下的类主要有四个MapperRegistry、MapperProxyFactory、MapperProxy和MapperMethod

映射注册类MapperRegistry

MapperRegistry是个注册类,它的knownMappers集合保存着Mapper接口和MapperProxyFactory实例的映射关系

它的addMapper()方法就是添加映射关系的方法:

public <T> void addMapper(Class<T> type) { if (type.isInterface()) { if (hasMapper(type)) { throw new BindingException("Type " type " is already known to the MapperRegistry."); } boolean loadCompleted = false; try { knownMappers.put(type, new MapperProxyFactory<>(type)); // It's important that the type is added before the parser is run // otherwise the binding may automatically be attempted by the // mapper parser. if the type is already known, it won't try. MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); parser.parse(); loadCompleted = true; } finally { if (!loadCompleted) { knownMappers.remove(type); } } } }

当传入的type是个接口并knownMappers中没有,就把type和对应的MapperProxyFactory实例放入knownMappers中

然后在执行sql的时候,Mybatis会调用MapperRegistry.getMapper()方法

@SuppressWarnings("unchecked") public <T> T getMapper(Class<T> type, SqlSession sqlSession) { final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " type " is not known to the MapperRegistry."); } try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " e, e); } }

  1. 先从knownMappers集合中找到对应的MapperProxyFactory实例
  2. 然后调用newInstance()方法
  3. 映射代理工厂类MapperProxyFactory
  4. MapperProxyFactory的newInstance()方法:

public T newInstance(SqlSession sqlSession) { final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } @SuppressWarnings("unchecked") protected T newInstance(MapperProxy<T> mapperProxy) { return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); }

生成mapperInterface接口 的代理对象的实例,代理类是MapperProxy,它实现了InvocationHandler,利用jdk动态代理生成代理对象

看一下它重写的invoke()方法:

映射代理类MapperProxy

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 { return cachedInvoker(method).invoke(proxy, method, args, sqlSession); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } }

不是Object的类会被拦截,拦截调用cachedInvoker()方法,其他执行invoke()方法,

private MapperMethodInvoker cachedInvoker(Method method) throws Throwable { try { return MapUtil.computeIfAbsent(methodCache, method, m -> { if (m.isDefault()) { try { if (privateLookupInMethod == null) { return new DefaultMethodInvoker(getMethodHandleJava8(method)); } else { return new DefaultMethodInvoker(getMethodHandleJava9(method)); } } catch (IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException e) { throw new RuntimeException(e); } } else { return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration())); } }); } catch (RuntimeException re) { Throwable cause = re.getCause(); throw cause == null ? re : cause; } }

  1. 从methodCache中获取对应的MapperMethodInvoker
  2. 如果缓存没有,如果是方法是default方法就创建DefaultMethodInvoker对象,否则创建PlainMethodInvoker对象
  3. 默认方法调用类DefaultMethodInvoker
  4. 对于DefaultMethodInvoker类通过MethodHandle完成调用

private static class DefaultMethodInvoker implements MapperMethodInvoker { private final MethodHandle methodHandle; public DefaultMethodInvoker(MethodHandle methodHandle) { super(); this.methodHandle = methodHandle; } @Override public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable { return methodHandle.bindTo(proxy).invokeWithArguments(args); } }

对于普通方法对应的类PlainMethodInvoker通过MapperMethod来完成调用,

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); } }总结

这篇文章主要介绍了聊聊Mybatis的binding模块,它的MapperRegistry保存着Mapper接口和MapperProxyFactory实例的映射关系,而MapperProxyFactory是一个的工厂,生成的是Mapper接口的代理类,MapperProxy实现InvocationHandler,重写invoke()方法进行拦截处理,根据方法判断是不是default类型创建不同的MethodInvoker类,然后调用MapperMethod执行sql,下篇文章我们将介绍MapperMethod类

,
图文教程
相关文章
热门专题
推荐软件
奇热小说
奇热小说
下载
QQ2019手机版
QQ2019手机版
下载
王者荣耀
王者荣耀
下载
百度浏览器迷你版
百度浏览器迷你版
下载
2345浏览器手机版
2345浏览器手机版
下载
网易邮箱
网易邮箱
下载
爱奇艺
爱奇艺
下载
网易云音乐
网易云音乐
下载
WPSOffice
WPSOffice
下载
优酷
优酷
下载
谷歌浏览器(Chrome)
谷歌浏览器(Chrome)
下载
迅雷看看播放器
迅雷看看播放器
下载
UC浏览器
UC浏览器
下载
QQ音乐
QQ音乐
下载
阿里旺旺买家版v9.12.10C官方版
阿里旺旺买家版v9.12.10C官方版
下载
360安全卫士v12.1官方版
360安全卫士v12.1官方版
下载
猜你喜欢
福路
福路
下载
阿里优品
阿里优品
下载
柯达305打印机驱动v7.8.5.2官方版
柯达305打印机驱动v7.8.5.2官方版
下载
KnotesMac版V1.0.2
KnotesMac版V1.0.2
下载
直不起的香肠人
直不起的香肠人
下载
爱生息
爱生息
下载
腾讯WeGame
腾讯WeGame
下载
StatusBarredMac版V3.2
StatusBarredMac版V3.2
下载
笨狼的学校生活
笨狼的学校生活
下载
爱千阳
爱千阳
下载
乐伴英语app
乐伴英语app
下载
整人表白软件v1.0免费版
整人表白软件v1.0免费版
下载
噬血代码女性模型替换成村雨MOD
噬血代码女性模型替换成村雨MOD
下载
ItchDesktopClient(多功能游戏平台)v25.4.1官方版
ItchDesktopClient(多功能游戏平台)v25.4.1官方版
下载
放逐之城1.06汉化补丁
放逐之城1.06汉化补丁
下载
从细胞到极点
从细胞到极点
下载