主题

  以前我一直有一个问题不懂.并且觉得很神奇.就是Mybatis我们开发的时候只需要定义接口,并没有写实现类,为什么我们运行的时候就可以直接使用? 现在我想分享下这部分大致是怎么实现的.

在启动的时候

根据之前的分享,在初始化阶段Build SqlSessionFactory的时候需要用到XMLConfigBuilder去parse XML文件生成Configuration对象,在 parse的步骤中其中有一步就是parse mappers节点

在parse mapper过程中会用到XMLMapperBuilder去parse.一步一步进入断点.

会发现后面会调用configuration的addMapper方法.它会调用MapperRegistry的addMapper方法

MapperRegistry相当用knownMappers这个hashmap于为每个Mapper注册一次,其中key是你自定义的Mapper接口的class,Value是MapperProxyFactory类的对象.

Factory一个就是一个工厂类,它肯定需要生产对应的对象,从名字上也能发现它生产的就是MapperProxy

  1. /**
  2. * Copyright 2009-2015 the original author or authors.
  3. * <p>
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. * <p>
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. * <p>
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.ibatis.binding;
  17.  
  18. import org.apache.ibatis.session.SqlSession;
  19.  
  20. import java.lang.reflect.Method;
  21. import java.lang.reflect.Proxy;
  22. import java.util.Map;
  23. import java.util.concurrent.ConcurrentHashMap;
  24.  
  25. /**
  26. * @author Lasse Voss
  27. */
  28. public class MapperProxyFactory<T> {
  29.  
  30. private final Class<T> mapperInterface;
  31. private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
  32.  
  33. public MapperProxyFactory(Class<T> mapperInterface) {
  34. this.mapperInterface = mapperInterface;
  35. }
  36.  
  37. public Class<T> getMapperInterface() {
  38. return mapperInterface;
  39. }
  40.  
  41. public Map<Method, MapperMethod> getMethodCache() {
  42. return methodCache;
  43. }
  44.  
  45. @SuppressWarnings("unchecked")
  46. protected T newInstance(MapperProxy<T> mapperProxy) {
  47. return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);
  48. }
  49.  
  50. public T newInstance(SqlSession sqlSession) {
  51. final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
  52. return newInstance(mapperProxy);
  53. }
  54.  
  55. }
  1. /**
  2. * Copyright 2009-2015 the original author or authors.
  3. * <p>
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. * <p>
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. * <p>
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.ibatis.binding;
  17.  
  18. import org.apache.ibatis.reflection.ExceptionUtil;
  19. import org.apache.ibatis.session.SqlSession;
  20.  
  21. import java.io.Serializable;
  22. import java.lang.reflect.InvocationHandler;
  23. import java.lang.reflect.Method;
  24. import java.util.Map;
  25.  
  26. /**
  27. * @author Clinton Begin
  28. * @author Eduardo Macarron
  29. */
  30. public class MapperProxy<T> implements InvocationHandler, Serializable {
  31.  
  32. private static final long serialVersionUID = -6424540398559729838L;
  33. private final SqlSession sqlSession;
  34. private final Class<T> mapperInterface;
  35. private final Map<Method, MapperMethod> methodCache;
  36.  
  37. public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
  38. this.sqlSession = sqlSession;
  39. this.mapperInterface = mapperInterface;
  40. this.methodCache = methodCache;
  41. }
  42.  
  43. @Override
  44. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  45. if (Object.class.equals(method.getDeclaringClass())) {
  46. try {
  47. return method.invoke(this, args);
  48. } catch (Throwable t) {
  49. throw ExceptionUtil.unwrapThrowable(t);
  50. }
  51. }
  52. final MapperMethod mapperMethod = cachedMapperMethod(method);
  53. return mapperMethod.execute(sqlSession, args);
  54. }
  55.  
  56. private MapperMethod cachedMapperMethod(Method method) {
  57. MapperMethod mapperMethod = methodCache.get(method);
  58. if (mapperMethod == null) {
  59. mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
  60. methodCache.put(method, mapperMethod);
  61. }
  62. return mapperMethod;
  63. }
  64.  
  65. }

从代码中我们可以得知,这里是用了JDK动态代理,MapperProxy类implements了InvocationHandler,

如果是调用自定义Mapper的Object类中的方法,比如toString,那就直接调用,否则的话调用mapperMethod.execute去执行对应的方法(比如selectById).那么mapperMethod是什么呢?

这个类的对象其实就是对应你写的Mapper里的方法,你的每个方法对应1个MapperMethod,相当于是Java的Method的包装.

另外还包含了你在XML里定义的SQL字符串, 是select还是insert还是update,delete操作等信息.相当于融合了你定义的Mapper里的Method和你为每个Method在XML里的写的信息.

这样你调用mapperMethod.execute的时候就能找到对应的SQL去执行了.

通过SqlSession获取Mapper

初始化完成后就如同之前的介绍,会在confuguration的mapperRegistry里注册好了各种MapperFactory.那么通过SqlSession去获取Mapper的时候也是类似的.会调用configuration去获取Mapper,内部会调用mapperRegistry去获取Mapper

然后通过MapperProxyFactory去创建一个MapperProxy并返还

小结

1.说白了,其实就是利用JDK动态代理,返回给你1个实现了你写的Mapper接口的对象,而其中的Invocation接口的实现类就是MapperProxy.

2.在初始化阶段会为你写的每个Mapper在Configuration的MapperRegistry里注册一个MapperFactory,当你要获取Mapper实例的时候就通过这个Factory来new.

3.当你调用Mapper.XXX方法的时候,比如select,就会调用MapperProxy的invoke方法,获取你定义在Mapper里的xxx方法对应的MapperMethod对象,这个对象就是Method的封装,同时在XML里找到对应的select语句再执行.

4.你写的每个Mapper类的对象对应1个MapperProxyFactory生成1个MapperProxy,你在Mapper中定义的每个方法对应1个MapperMethod,它是Java的Method的封装

  

MyBatis 学习记录2 Mapper对象是如何生成的的更多相关文章

  1. MyBatis 学习记录5 MyBatis的二级缓存

    主题 之前学习了一下MyBatis的一级缓存,主要涉及到BaseExecutor这个类. 现在准备学习记录下MyBatis二级缓存. 配置二级缓存与初始化发生的事情 首先二级缓存默认是不开启的,需要自 ...

  2. MyBatis 学习记录3 MapperMethod类

    主题 之前学习了一下MapperProxy的生产过程,自定义Mapper类的对象是通过动态代理生产的,调用自定义方法的时候实际上是调用了MapperMethod的execute方法:mapperMet ...

  3. mybatis 学习记录1

    起因 以前刚学习java三大框架的时候持久层框架我是自学的是hibernate..感觉蛮好用的,so easy..后来大三实习公司用的是jpa(hibernate外包装一层)...再后来工作1年多用的 ...

  4. MyBatis 学习记录7 一个Bug引发的思考

    主题 这次学习MyBatis的主题我想记录一个使用起来可能会遇到,但是没有经验的话很不好解决的BUG,在特定情况下很容易发生. 异常 java.lang.IllegalArgumentExceptio ...

  5. MyBatis 学习记录6 TypeHandler

    主题 因为对MyBatis在JDBC数据和Java对象之间数据转化比较感兴趣,所以就记录并学习一下TypeHandler. 使用场景 如上图所示,观察下接口方法就能明白.TypeHandler主要用于 ...

  6. MyBatis 学习记录4 MyBatis的一级缓存

    主题 分享记录一下MyBatis的一级缓存相关的学习. Demo public static void firstLevelCache() { init("mybatis-config.xm ...

  7. mybatis学习记录六——一对一、一对多和多对多查询

    9       订单商品数据模型 9.1     数据模型分析思路 1.每张表记录的数据内容 分模块对每张表记录的内容进行熟悉,相当 于你学习系统 需求(功能)的过程. 2.每张表重要的字段设置 非空 ...

  8. Mybatis学习记录(六)----Mybatis的高级映射

    1.一对多查询 1.1 需求 查询订单及订单明细的信息. 1.2 sql语句 确定主查询表:订单表 确定关联查询表:订单明细表 在一对一查询基础上添加订单明细表关联即可. SELECT orders. ...

  9. Mybatis学习记录(五)----Mybatis的动态SQL

    1.  什么是动态sql mybatis核心 对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接.组装. 1.1 需求 用户信息综合查询列表和用户信息查询列表总数这两个statemen ...

随机推荐

  1. 在制作跨平台的 NuGet 工具包时,如何将工具(exe/dll)的所有依赖一并放入包中

    NuGet 提供了工具类型的包支持,生成一个基于 .NET Core 的 dll 或者基于 .NET Framework 的 exe 之后,你几乎可以对项目做任何事情.但是,默认情况下,NuGet 不 ...

  2. vector 介绍

    介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和for_each()中的使用.通 ...

  3. 《DSP using MATLAB》示例Example 8.29

    %% ------------------------------------------------------------------------ %% Output Info about thi ...

  4. test20181029 思考熊的马拉松

    题意 思考熊的马拉松 问题描述 今年,n只思考熊参加了校园马拉松比赛.马拉松的赛道是环形的,每圈的长度是A,完成比赛需要跑L圈. 比赛中,甲领先乙很长距离,绕过一圈或多圈后从后面追上了乙的现象叫做&q ...

  5. chrome安装vue-devtools

    安装方法1: 需正常打开chrome商店,搜索vuejs devtools 安装.chrome://extensions/ 开发者工具-扩展程序下启用: 方法2: github下载插件,npm包安装依 ...

  6. ffmpeg hls 点播负载均衡简单实现

    备注: 主要是进行文件的切片处理,以及m3u8 的文件前缀添加以达到通过nginx 或者类似的分布式文件工具进行数据切片处理 参考配置如下: ffmpeg -y -i mydemo.mp4 -vcod ...

  7. struts 2整合spring要注意的问题(二)

    在 struts2_spring_plugin.xml配置文件里有一个strus.objectFactory.spring.autoWire 属性 默认值为name   也就是说你不想装载.它都会找个 ...

  8. oracle之 RAC Interconnect之HAIP

    0. 背景 Oracle 从11.2.0.2开始引入了一个新特性叫做Redundant Interconnect,简称HAIP.HAIP的目的用来代替操作系统级别的网卡绑定以实现Active-Acti ...

  9. 生产环境LNMP (交友)

    一. 下载一键安装包 LNMP   官方地址为:http://lnmp.org/ 原生产环境为 : php5.4.32  mysql 5.5  nginx 1.40   我们用LNMP包安装相应的环境 ...

  10. (转)Inno Setup入门(八)——有选择性的安装文件

    本文转载自:http://blog.csdn.net/yushanddddfenghailin/article/details/17250827 这主要使用[Components]段实现,一个演示的代 ...