主题

  以前我一直有一个问题不懂.并且觉得很神奇.就是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

 /**
* Copyright 2009-2015 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.binding; import org.apache.ibatis.session.SqlSession; import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; /**
* @author Lasse Voss
*/
public class MapperProxyFactory<T> { private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>(); public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
} public Class<T> getMapperInterface() {
return mapperInterface;
} public Map<Method, MapperMethod> getMethodCache() {
return methodCache;
} @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<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
} }
 /**
* Copyright 2009-2015 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.binding; import org.apache.ibatis.reflection.ExceptionUtil;
import org.apache.ibatis.session.SqlSession; import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map; /**
* @author Clinton Begin
* @author Eduardo Macarron
*/
public class MapperProxy<T> implements InvocationHandler, Serializable { private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache; public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
} @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);
} private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
} }

从代码中我们可以得知,这里是用了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. {Reship}{Socket}C#简单应用

    This article come frome here ======================================================================= ...

  2. matplotlib ----- 同一线条的不同颜色

    对同一线条的各个段或者特殊点,  用不同的颜色. 参考下面 http://stackoverflow.com/questions/30121773/python-is-it-possible-to-c ...

  3. Spring核心机制:依赖注入

    转载:http://www.cnblogs.com/chenssy/ Java应用(从applets的小范围到全套n层服务端企业应用)是一种典型的依赖型应用,它就是由一些互相适当地协作的对象构成的.因 ...

  4. (高级篇)jQuery学习之jQuery Ajax用法详解

    jQuery Ajax在web应用开发中很常用,它主要包括有ajax,get,post,load,getscript等等这几种常用无刷新操作方法,下面我来给各位同学介绍介绍. 我们先从最简单的方法看起 ...

  5. C语言控制台窗体图形界面编程(八):鼠标事件

           上次讲的是键盘事件,这次我们介绍鼠标事件. 以下先介绍下鼠标事件的结构体以及相关信息. typedef struct _MOUSE_EVENT_RECORD //鼠标事件结构体 { CO ...

  6. Google服务,你都用了多少?

    今天无意中发现这些东西,Google提供的服务还真是多,大家经常用到的不知道有哪些呢?就我个人而言,经常用到的就是Google搜索,Gmail邮箱,还有Google论坛了. Google Ad Sen ...

  7. Discuz! X2.5RC 全新安装图文教程

    http://www.discuz.net/thread-2660015-1-1.html 一步步教你利用Discuz X2.5建设论坛视频教程(174集) http://down.51cto.com ...

  8. java的时间

    先看例子: import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; imp ...

  9. WiresShark使用说明

    WiresShark是号称全世界最流行的网络分析工具(它的官网自己说的).下载地址:https://www.wireshark.org/#download,目前最新版本是2.6.2.我本地用的是汉化的 ...

  10. 3、MR开发入门

    1.预先准备2个文件file1.txt和file2.txt.文件内容为网页上摘下,不具有代表性,只为举例. file1.txt内容为: With this setup, whenever you ch ...