在《mybatis源码分析:启动过程》中分析了mybatis的启动过程,mybatis的启动过程主要集中在解析其核心配置文件(mybatis-config.xml)上,把配置文件中的配置全部解析到Configuration类中,每个配置在Configuration中均能找到其设置。本文分析mybatis中的查询接口(例,UserMapper)。

一、概述

在编写mybatis的程序时,常见的做法时编写一个Mapper接口,再编写相应的映射文件,之后便可以初始化mybatis的环境,调用该接口的方法执行操作数据库的各中操作。那么Mapper接口是什么对象那,是怎样和映射文件关联,最后又怎样执行方法的。今天先分析Mapper接口,具体的环境可参考《mybatis源码分析:启动过程》中的相关代码。这里先给出一个结论,Mapper接口是使用JDK代理生成的一个代理类。

二、详述

上面说到Mapper接口是使用JDK动态代理生成的一个代理类,下面通过代码去分析,下面是我测试的代码片段,

package cn.com.mybatis.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List; import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder; import cn.com.mybatis.dao.UserMapper; public class TestMybatis { public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
System.out.println(ClassLoader.getSystemClassLoader());
System.out.println(Resources.class.getClassLoader());
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(inputStream);
SqlSession session=factory.openSession();
UserMapper userMapper=session.getMapper(UserMapper.class);
// session.insert("");
System.out.println("userMapper:"+userMapper); userMapper.getUser(); } }

上面从SqlSession中调用getMapper方法,传入一个XXMapper.class的参数,这里传入UserMapper.class(必须是接口 ?),返回的是一个UserMapper的对象,那么这个返回的值到底是什么那,我们分析源码。我们值得这里的session是一个DefaultSqlSession对象,看其方法,

@Override
public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}

调用了Configuration对象的getMapper方法,

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}

调用了mapperRegistry的getMapper方法,

@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//根据Class对象获得一个MapperProxyFactory
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
//生成一个目标对象的JDK代理对象,并返回
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}

从上面可以看到从knownsMappers中根据type返回一个MapperProxyFactory,直译过来就是Mapper接口的代理工厂,mybatis的无处不在的工厂模式啊。

下面看knownsMappers的定义,

从上面可以看出knownMappers中使用map存储,其值为MapperProxyFactory,看下MapperProxyFactory的定义,

从上面可以看到该类有一个构造方法,该构造方法的参数也是一个Class对象,参数名称为mapperInterface,从方法名直译过来就是我们写的Mapper接口。

上面了解了knownsMappers和MapperProxyFactory后,可以知道knownsMappers中的value是根据Mapper接口生成的,那么取出来的值必为当前key的一个MapperProxyFactory,即该对象中的mapperInterface为key值。

根据Class取出其对应的MapperProxyFactory后,下面调用其newInstance方法,如下

下面看其newInstance方法,

public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}

生成一个MapperProxy对象,

public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}

上面仅是给三个字段赋值,再看后面的方法,MapperProxyFactory的newInstance(mapperProxy)方法,

@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
//JDK动态代理
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

从上面可以看到是标准的JDK动态代理生成对象的放式,不再赘述。从这里看出返回的是一个Mapper接口的动态代理对象,第三个参数mapperProxy必然实现了InvocationHandler接口,看其定义

可以看到实现了InvocationHandler接口,那么在调用Mapper接口的时候肯定会执行MapperProxy的invoke方法,这里执行过程下次再分析。

三、总结

本文分析了mybatis中Mapper接口的类型,即从mybatis中取出时是什么类型,这里是一个JDK的动态代理,所以我们要写的是一个接口,因为JDK动态代理是基于接口生成一个代理实现类。

原创不易,有不正之处欢迎指正。

mybatis源码分析:Mapper接口是什么的更多相关文章

  1. MyBatis 源码分析——SqlSession接口和Executor类

    mybatis框架在操作数据的时候,离不开SqlSession接口实例类的作用.可以说SqlSession接口实例是开发过程中打交道最多的一个类.即是DefaultSqlSession类.如果笔者记得 ...

  2. MyBatis源码分析(3)—— Cache接口以及实现

    @(MyBatis)[Cache] MyBatis源码分析--Cache接口以及实现 Cache接口 MyBatis中的Cache以SPI实现,给需要集成其它Cache或者自定义Cache提供了接口. ...

  3. 精尽MyBatis源码分析 - MyBatis初始化(二)之加载Mapper接口与XML映射文件

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  4. MyBatis源码分析-MyBatis初始化流程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

  5. MyBatis源码分析-SQL语句执行的完整流程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

  6. MyBatis源码分析(5)——内置DataSource实现

    @(MyBatis)[DataSource] MyBatis源码分析(5)--内置DataSource实现 MyBatis内置了两个DataSource的实现:UnpooledDataSource,该 ...

  7. 【MyBatis源码分析】select源码分析及小结

    示例代码 之前的文章说过,对于MyBatis来说insert.update.delete是一组的,因为对于MyBatis来说它们都是update:select是一组的,因为对于MyBatis来说它就是 ...

  8. MyBatis源码分析之环境准备篇

    前言 之前一段时间写了[Spring源码分析]系列的文章,感觉对Spring的原理及使用各方面都掌握了不少,趁热打铁,开始下一个系列的文章[MyBatis源码分析],在[MyBatis源码分析]文章的 ...

  9. Mybatis源码分析-BaseExecutor

    根据前文Mybatis源码分析-SqlSessionTemplate的简单分析,对于SqlSession的CURD操作都需要经过Executor接口的update/query方法,本文将分析下Base ...

  10. mybatis源码分析(一)

    mybatis源码分析(sqlSessionFactory生成过程) 1. mybatis框架在现在各个IT公司的使用不用多说,这几天看了mybatis的一些源码,赶紧做个笔记. 2. 看源码从一个d ...

随机推荐

  1. Android OpenMAX(六)OMXStore

    在前面两节的学习中我们知道了OMX Core是用来管理(查询/创建/销毁)Android平台上的硬件编解码组件的.这一节我们再向上一层,Android平台除了提供有硬件编解码组件支持,还内置了一些软件 ...

  2. .NET周刊【5月第4期 2024-05-26】

    国内文章 开源低代码框架 ReZero API 正式版本发布 ,界面操作直接生成API https://www.cnblogs.com/sunkaixuan/p/18201175 ReZero是一款. ...

  3. 在Rainbond中一键部署高可用 EMQX 集群

    本文描述如何通过云原生应用管理平台 Rainbond 一键安装高可用 EMQX 集群.这种方式适合不太了解 Kubernetes.容器化等复杂技术的用户使用,降低了在 Kubernetes 中部署 E ...

  4. Yii AR事务操作

    Yii Ar事务操作,示例代码如下: $model=Post::model(); $transaction=$model->dbConnection->beginTransaction() ...

  5. 【论文笔记】SegNet

    [深度学习]总目录 SegNet是Cambridge提出旨在解决自动驾驶或者智能机器人的图像语义分割深度网络,开放源码,基于caffe框架.SegNet运用编码-解码结构和最大池化索引进行上采样,最主 ...

  6. C++笔记(8)常规new运算符和定位new运算符

    通常,new负责在堆(heap)中找到一个能够满足要求的内存块.new运算符还有一种变体,被称为定位(placement)new运算符,他能让你能够指定要使用的位置.程序员可以使用这种特性来设置其内存 ...

  7. JDBC的简单使用以及介绍

    JDBC(Java DataBase Connectivity) Java 语言连接数据库 再本模块中,java提供里一组用于连接数据库的类和接口 Java 语言开发者,本身没有提供如何具体连接数据库 ...

  8. Linux扩展篇-shell编程(五)-流程控制(四)-while语句

    基本语法: while [ condition ] do statement done 或 while [ condition ]; do statement done 注意事项: 实践:

  9. realtek高清晰音频管理器 WIN10

    在WIN10里已经改名了: Realtek Audio Console . 在安装realtek声卡驱动后,Realtek Audio Console 会自动安装.

  10. Scrapy爬取知名技术文章网站

    scrapy安装以及目录结构介绍 创建有python3的虚拟环境 mkvirtualenv mkvirtualenv py3env 安装scrapy 进入虚拟环境py3env,把pip的源设置为豆瓣源 ...