聊聊Mybatis的binding模块

网友投稿 810 2022-10-20

聊聊Mybatis的binding模块

聊聊Mybatis的binding模块

聊聊Mybatis的binding模块

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

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

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

public void addMapper(Class 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

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

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

@SuppressWarnings("unchecked") public T getMapper(Class type, SqlSession sqlSession) { final MapperProxyFactory mapperProxyFactory = (MapperProxyFactory) 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: "

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

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

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

看一下它重写的invoke()方法: 映射代理类MapperProxy

MapperProxy的invoke()方法:

@Override public Object invoke(Object proxy, Method method, Object[] args) throws{ 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

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

private MapperMethodInvoker cachedInvoker(Method method) throws{ 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

从methodCache中获取对应的MapperMethodInvoker如果缓存没有,如果是方法是default方法就创建DefaultMethodInvoker对象,否则创建PlainMethodInvoker对象默认方法调用类DefaultMethodInvoker对于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{ return

对于普通方法对应的类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{ return

总结

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

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:PatatiumAppUi- App 自动化测试框架
下一篇:RestTemplate文件上传下载与大文件流式下载
相关文章

 发表评论

暂时没有评论,来抢沙发吧~