02.MyBatis 源码分析之获取实现类

Mybatis Mapper接口是如何找到实现类的-源码分析 转载自:https://www.cnblogs.com/demingblog/p/9544774.html KeyWords: Mybatis 原理,源码,Mybatis Mapper 接口实现类,代理模式,动态代理,Java动态理,Proxy.newProxyInstance,Mapper 映射,Mapper 实现 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及... 阅读详情

1. 时序图

MyBatis -getMapper 时序图

2. 通过 getMapper 获取实现类

@Test
public void test() throws IOException {
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    // 1、获取 sqlSessionFactory 对象
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    // 2、获取 sqlSession 对象       ------> 3
    SqlSession openSession = sqlSessionFactory.openSession();
    try {
        // 3、获取接口的实现类       ------> 4
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        // 4、执行目标方法
        Employee employee = mapper.getEmpById(1);
        System.out.println(employee);
    } finally {
        openSession.close();
    }
}

3. 获取 SqlSession

3.1 DefaultSqlSessionFactory#openSession
  • org.apache.ibatis.session.defaults.DefaultSqlSessionFactory
@Override
public SqlSession openSession() {
    // configuration.getDefaultExecutorType()       ------> 3.2
    // openSessionFromDataSource(),从数据库中获取  SqlSession       ------> 3.3
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
3.2 Configuration#getDefaultExecutorType
  • org.apache.ibatis.session.Configuration
public ExecutorType getDefaultExecutorType() {
    // ExecutorType defaultExecutorType = ExecutorType.SIMPLE,即返回一个 simpleExecutorType
    return defaultExecutorType;
}
3.3 DefaultSqlSessionFactory#openSessionFromDataSource
  • org.apache.ibatis.session.defaults.DefaultSqlSessionFactory
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      // 从 configuration 中获取 environment
      final Environment environment = configuration.getEnvironment();
      // 从 environment 获取 transactionFactory
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      // 根据数据库的配置,创建一个 transaction
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      // 创建一个 executor 执行器       ------> 3.4
      final Executor executor = configuration.newExecutor(tx, execType);
      // 创建一个 DefaultSqlSession 对象,传入了 configuration、executor
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
}
3.4 Configuration#newExecutor
  • org.apache.ibatis.session.Configuration
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      // 创建一个 SimpleExecutor
      executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
      // 如果开启了缓存,创建一个 CachingExecutor,包装 SimpleExecutor,装饰模式
      executor = new CachingExecutor(executor);
    }
    // 用插件包装 CachingExecutor       ------> 3.5
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
}
3.5 InterceptorChain#pluginAll
  • org.apache.ibatis.plugin.InterceptorChain
public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      // 调用插件的 plugin 方法包装 executor 后返回
      target = interceptor.plugin(target);
    }
    return target;
}

4. 调用 getMapper 获取实现类

4.1 DefaultSqlSession#getMapper
  • org.apache.ibatis.session.defaults.DefaultSqlSession
@Override
public <T> T getMapper(Class<T> type) {
    // 调用 configuration.getMapper() 方法      ------> 4.2
    return configuration.<T>getMapper(type, this);
}
4.2 Configuration#getMapper
  • org.apache.ibatis.session.Configuration
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // 调用 mapperRegistry.getMapper() 方法      ------> 4.3
    return mapperRegistry.getMapper(type, sqlSession);
}
4.3 MapperRegistry#getMapper
  • org.apache.ibatis.binding.MapperRegistry
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // 获取 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 {
      // 调用 mapperProxyFactory.newInstance() 方法     ------> 4.4
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
}
4.4 MapperProxyFactory#newInstance
  • org.apache.ibatis.binding.MapperProxyFactory
public T newInstance(SqlSession sqlSession) {
    // 构建 mapperProxy 对象
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    // 调用 newInstance() 方法      ------> 4.5
    return newInstance(mapperProxy);
}
4.5 MapperProxyFactory#newInstance
  • org.apache.ibatis.binding.MapperProxyFactory
protected T newInstance(MapperProxy<T> mapperProxy) {
    // 用 jdk 的动态代理生产实现类      ------> 4.6
    // 注意此处是为 mapperProxy 生成代理类,并非是为 XxxMapper 生成,这样就不需要 XxxMapper 的实现类了
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
4.6 Proxy#newProxyInstance
  • java.lang.reflect.Proxy
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
{
    Objects.requireNonNull(h);

    final Class<?>[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    // 断点到此处,可调用 cl.getMethods() 查看所有方法
    Class<?> cl = getProxyClass0(loader, intfs);

    ...
    
}
  • mapperProxy 会为 getEmpById() 方法生成代理方法,所有的代理方法如下
0 = {Method@1751} "public final boolean com.sun.proxy.$Proxy4.equals(java.lang.Object)"
1 = {Method@1752} "public final java.lang.String com.sun.proxy.$Proxy4.toString()"
2 = {Method@1753} "public final int com.sun.proxy.$Proxy4.hashCode()"
3 = {Method@1754} "public final pers.mangseng.study.mybatis.pojo.Employee com.sun.proxy.$Proxy4.getEmpById(java.lang.Integer)"
4 = {Method@1755} "public static boolean java.lang.reflect.Proxy.isProxyClass(java.lang.Class)"
5 = {Method@1756} "public static java.lang.Object java.lang.reflect.Proxy.newProxyInstance(java.lang.ClassLoader,java.lang.Class[],java.lang.reflect.InvocationHandler) throws java.lang.IllegalArgumentException"
6 = {Method@1757} "public static java.lang.reflect.InvocationHandler java.lang.reflect.Proxy.getInvocationHandler(java.lang.Object) throws java.lang.IllegalArgumentException"
7 = {Method@1758} "public static java.lang.Class java.lang.reflect.Proxy.getProxyClass(java.lang.ClassLoader,java.lang.Class[]) throws java.lang.IllegalArgumentException"
8 = {Method@1759} "public final void java.lang.Object.wait() throws java.lang.InterruptedException"
9 = {Method@1760} "public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException"
10 = {Method@1761} "public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException"
11 = {Method@1762} "public final native java.lang.Class java.lang.Object.getClass()"
12 = {Method@1763} "public final native void java.lang.Object.notify()"
13 = {Method@1764} "public final native void java.lang.Object.notifyAll()"
MyBatis缓存Cache源码分析 一、缓存接口介绍 MyBatis的一级缓存和二级缓存都是使用的Cache接口实现类,它的方法定义如下: public interface Cache { String getId(); void putObject(Object key, Object value); Object getObject(Object key); Object removeObject... 阅读详情

相关推荐

【项目实战】MyBatis的基础源码 —— MapperProxy(Mapper接口的代理类)源码介绍

MapperProxy是MyBatis中的一个重要类,它是Mapper接口的代理类。

奶爸的编程之路,也就一周冷个三天 937

Mybatis四大核心对象及四大内置对象

Mybatis四大核心对象及四大内置对象

kouguoguo的博客 2054

[数字电路]用与非门实现BCD译码器驱动数码管

Hello,大家好。这里是xdd_core,好久不见。今天来和大家聊聊大一数字电路课程的一个课设。# Key word:BCD Decoder,Proteus8.x,NAND Gate,Digital Circuit# 流程:Proteus8.x仿真电路并绘制PCB导出Gerber文件打样,最终实物验证。# 以下为我对这个课设的report(里面对整个设计做了详细介绍,并设计了完整的验证电路) 感谢观看,仅供参考,未经作者允许,禁止转载/抄袭,本文已上传至数据库,查重必挂QAQ BCD to 7-Segme

xddcore的博客 6012

Mybatis Mapper接口如何找到实现类

1、前言        MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。我们在使用 Mybaits 进行开发 ,通常只需要定义几个 Mapper 接口,然后在编写一个 xml 文件,我们在配置文件中写好 sql , Mybatis 帮我们完成 M...

Vincent2014Linux 2766

最全中文停用词表(可直接复制)

最全的停用此表整理 词表名 词表文件 中文停用词表 cn_stopwords.txt 哈工大停用词表 hit_stopwords.txt 百度停用词表 baidu_stopwords.txt 机器智能实验室停用词库 scu_stopwords.txt 以上停用词表链接:https://github.com/goto456/stopwords 以下是我常用的1893个停用词,可直接复制 ! " # $ % & ' ( ) * + , - -- . .. ... ....

dilifish的博客 12万+

(Linux)DHCP 超级作用域和中继代理(超难受做了超久)

DHCP服务器在192.168.159.0 可以实现分配IP的功能,现在要跨网段分配IP 就需要用到DHCP中继代理。中继代理有两张网卡分别eth0:IP 192.168.159.2 ;eth1: IP:192.168.200.2 。现在要实现192.168.200.0网段的客户机可以获取DHCP服务器的IP。中继代理其实是相当于一个路由器的作用 DHCP服务器的IP地址 :192.168.159...

DJ_joker的博客 2225

Mybatis源码解析(八):Mapper代理原理

文章主要围绕着如下几个点,展开源码解析:是如何进行解析的?是如何生成的代理对象?是怎么完成的增删改查操作?标签配置的包名下的Mapper接口文件都会被加载成对应的代理类工厂通过Mapper接口获取同包同名的xml文件,并解析Mapper接口通过jdk代理创建代理类,接口方法匹配xml中标签的id值,执行增删改查。

从基础到源码解析的学习记录 3125

STM32硬件SPI配置为全双工模式下不要单独使用HAL_SPI_Transmit API及HAL_SPI_TransmitReceive改造方法

STM32 HAL库中SPI全双工模式使用问题总结:当配置为全双工模式时,单独使用HAL_SPI_Transmit会导致后续接收数据异常,原因是该API未处理接收数据。改造HAL_SPI_TransmitReceive使其支持单纯的发送/接收模式:当pTxData为NULL时只关心接收数据,pRxData为NULL时只关心发送数据,但仍会保持全双工通信。建议在全双工模式下统一使用改造后的HAL_SPI_TransmitReceive函数。

kevin1499的博客 901

探秘MyBatis缓存原理:Cache接口与实现类源码分析

MyBatis的缓存是提高数据库访问性能的关键机制之一,而Cache接口及其实现类则是其核心组件。本文将深入研究MyBatis缓存机制,详细解析Cache接口及其常用实现类的源码。我们将探讨一级缓存和二级缓存的工作原理,以及不同实现类的特点和适用场景。通过分析源码,读者将能够深入理解MyBatis缓存机制的内部实现,并掌握如何定制和优化缓存功能。

学而时习之,不亦说乎?温故而知新,可以为师矣! 9479

CloudCompare 多窗口联动显示点云

CloudCompare支持多窗口联动显示多个点云数据,可以用来比对原始点云数据与语义分割后的结果。 一、创建多个视窗 打开CloudCompare后会默认有一个视图,我们要同时打开两个数据就需要再创建一个视图,选择菜单栏里的3D Views,在下拉菜单中点击new,这样就创建了一个新的视图,这时3D Views的下拉菜单中有3D View 1和3D View 2两个视图,然后点击3D Views下拉菜单中的Title,这时在数据展示区就会出现两个并列的窗口。 二、分别加载点云数据 将数据分别拖进两个

zhaoguanhua的博客 2740

[特殊字符] 从零构建携程/飞猪机票价格爬虫:Python异步抓取与反爬对抗实战

在出行决策、竞品分析、价格预测模型训练等场景中,稳定获取携程(Ctrip)和飞猪(Fliggy)的实时机票价格波动数据是刚需。然而,这两大平台均部署了业界顶尖的反爬体系——包括但不限于:动态请求签名(SignToken设备指纹采集(UACanvasWebGL接口参数加密(X-Sign_abtestcookie混淆)频率限制与 IP 封禁(滑动窗口 + 行为检测)目录前言:为什么需要自建机票价格爬虫?一、技术选型与项目架构1.1 核心技术栈1.2 系统架构图(文字描述)1.3 法律与道德声明。

2201_76125261的博客 338

Mybatis Mapper接口实现类的源码分析

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。我们在使用 Mybaits 进行 ,通常只需要定义几个 Mapper 接口,然后在编写一个 xml 文件,我们在配置文件中写好 sql , Mybatis 帮我们完成 Mapper 接口道具体实现的调用。以及将结果映射到 mode...

bug_remover的博客 598

【人工智能】Cursor模型被封?两步教你破解

Cursor模型全线被禁,主流模型如Claude、GPT-4无法访问,仅剩Deepseek等基础模型可用。官方证实限制源于上游API区域政策,提供三种"无效"解决方案引发用户不满。社区发现有效解决方式:需同时开启全局代理和将Cursor网络设置改为HTTP/1.1协议,详细步骤包括修改用户设置和完全重启程序。另有SOCKS5代理配置方案供高级用户选择。技术原理推测HTTP/1.1可绕过区域检测。用户面临继续使用或转投其他工具的选择,社区交流受限但仍有讨论。

奶爸的编程之路,也就一周冷个三天 2194

mybatis的mapper为啥只有接口没有实现类,它却能工作?

这时候,我们发现Configuration里面出现了一个mapperRegistry,翻译过来可以理解为mapper的注册器,其实在加载UserMapper.xml的时候,我们就需要在mapperRegistry里面进行注册,所有,我们可以从这里面进行获取。那么只能是动态代理,动态代理接口的所有方法,每次接口被调用,就会进入动态代理对象的invoke方法,然后加载xml中的sql完成操作数据库,再返回结果。所以,动态代理代理还是对象类,那么我们只有接口,不能new,哪来的对象呢?,就是反射生成的这个对象。

LoveSummer 1万+

Unity零基础到入门 ☀️| 小万字教程 对 Unity 中的 协程 ❤️全面解析+实战演练❤️

Unity,为了让Unity基础知识专栏更加完善,又肝了一篇协程来学习。 协程在Unity中还是很常用的,一起来看一下协程的基本概念和使用方法吧!

努力前行,总会成为自己心中的那道光 8万+

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

MyBatis 源码分析--获取SqlSession

前文我们从源码层面梳理了 SqlSessionFactory 的创建过程,本篇我们继续分析一下 SqlSession 的获取过程。

weixin_42118323的博客 2212

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

【Mybatis】源码分析-深入源码

问题在开发过程中很多时候我们并不需要总是在加载⽤户信息时就⼀定要加载他的订单信息。此时就是我们所说的延迟加载。在⼀对多中,当我们有⼀个⽤户,它有个100个订单。在查询⽤户的时候,要不要把关联的订单查出来?在查询订单的时候,要不要把关联的⽤户查出来?在查询⽤户时,⽤户下的订单应该是,什么时候⽤,什么时候查询。在查询订单时,订单所属的⽤户信息应该是随着订单⼀起查询出来。就是在需要⽤到数据时才进⾏加载,不需要⽤到数据时就不加载数据。延迟加载也称懒加载。

下半夜的风 4539

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

MyBatis 源码分析 - 缓存原理

在 MyBatis 中,Cache 是缓存接口,定义了一些基本的缓存操作,所有缓存类都应该实现该接口。MyBatis 内部提供了丰富的缓存实现类,比如具有基本缓存功能的 PerpetualCache,具有 LRU 策略的缓存 LruCache,以及可保证线程安全的缓存 SynchronizedCache 和具备阻塞功能的缓存 BlockingCache 等。除此之外,还有很多缓存实现类,这里就不一一列举了。需要特别说明的是,MyBatis 在实现缓存模块的过程中,使用了装饰模式。

攻城狮不是猫 993

Mybatis3.5.4源码分析-3- 获取mapper,反射调用查询

BlogMapper mapper = session.getMapper(BlogMapper.class); mybatis中,通过session.getMapper来获取mapper接口的实现类,同样的,ctrl+alt+B 进入这个方法的默认实现 org.apache.ibatis.session.defaults.DefaultSqlSession#getMapper 中: @Override public <T> T getMapper(Class<T> t.

weixin_41300437的博客 1592

Mybatis从创建SQLSessionFactory到获取Mapper源码分析

目录1.写在前面2.获取SqlSessionFactory对象3.获取SqlSession对象4.获取Mapper 1.写在前面 (1).InputStream in = Resources.getResourceAsStream("mybatis-config.xml"); (2).SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in); (3).SqlSession sqlSession = sqlS

shangshanzixu的博客 1276

MyBatis 源码分析 - 插件机制

文章目录1.简介2. 插件机制原理3. 源码分析3.1 植入插件逻辑3.2 执行插件逻辑4. 实现一个分页插件5. 总结 1.简介 一般情况下,开源框架都会提供插件或其他形式的拓展点,供开发者自行拓展。这样的好处是显而易见的,一是增加了框架的灵活性。二是开发者可以结合实际需求,对框架进行拓展,使其能够更好的工作。以 MyBatis 为例,我们可基于 MyBatis 插件机制实现分页、分表,监控等功能。由于插件和业务无关,业务也无法感知插件的存在。因此可以无感植入插件,在无形中增强功能。 开发 MyBatis

ThinkWon的博客 2365

MyBatis 源码分析 - 内置数据源

文章目录1.简介2.内置数据源初始化过程3.UnpooledDataSource3.1 初始化数据库驱动3.2 获取数据库连接4.PooledDataSource4.1 辅助类介绍4.2 获取连接4.3 回收连接4.4 小节5.总结 1.简介 本篇文章将向大家介绍 MyBatis 内置数据源的实现逻辑。搞懂这些数据源的实现,可使大家对数据源有更深入的认识。同时在配置这些数据源时,也会更清楚每种属性的意义和用途。因此,如果大家想知其然,也知其所以然。那么接下来就让我们一起去探索 MyBatis 内置数据源的源

ThinkWon的博客 1885

mybatis源码分析

mybatis源码

qq_52219290的博客 1446

mybatis拦截器源码分析

mybatis拦截器源码分析 拦截器简介 mybatis Plugins 拦截器 由于Mybatis对数据库访问与操作进行了深度的封装,让我们应用开发效率大大提高,但是灵活度很差 拦截器的作用:深度定制Mybatis的开发 抛出一个需求 :获取Mybatis在开发过程中执行的SQL语句(执行什么操作获取那条SQL语句) ​ 在JDBC中我们的sql都会直接定义出来,所以实现上面这个需求很简单.但是在Mybatis中由于深度封装导致不好进行灵活满足需求,所以Mybatis拦截器可以用来解决这一系列问题

helloworld工程师的博客 865

spring集成Mybatis源码分析

1、开启事务,创建TransactionInfo保存事务相关信息,获取连接并上下文TransactionSynchronizationManager2.执行事务方法3.业务层调用mybatis,mybatis创建sqlSession并保存到上下文TransactionSynchronizationManager,同时mybatis注册自己的TransactionSynchronization实现提供事务周期各阶段的回调,等待spring回调协同事务工作。

weixin_50309827的博客 1244
上一篇: 01.MyBatis 源码分析之解析 xml
下一篇: 03.MyBatis 源码分析之增删改查
masteryourself
博客等级 码龄9年 13粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值