前言

注意:

学习源码一定一定不要太关注代码的编写,而是注意代码实现思想:

通过设问方式来体现代码中的思想;方法:5W+1H

源代码: https://gitee.com/xbhog/mybatis-xbhog https://github.com/xbhog/mybatis-xbhog ;交个朋友,有价值欢迎star。

回顾&分析

上一局实现Mapper接口和映射器通过代理类的方式进行链接。

上一局测试类:【简写MyBatis】01-简单映射器;虽然基本功能实现了,但是还不智能,可以发现该测试类中的映射器代理工厂只能实现单一的接口代理,SqlSession也需要规范化处理;将映射器代理和方法的调用类似服务进行包装。

 @Test
 public void test_MapperProxyFactory() {
     MapperProxyFactory<IUserDao> factory = new MapperProxyFactory<>(IUserDao.class);
 ​
     Map<String, String> sqlSession = new HashMap<>();
     sqlSession .put("com.xbhog.IUserDao.getUserName","模拟执行 Mapper.xml 中 SQL 语句的操作:查询用户姓名");
     IUserDao userDao = factory.newInstance(sqlSession);
 ​
     String res = userDao.queryUserName("10001");
     logger.info("测试结果:{}", res);
 }

目的

  1. 根据包路径实现接口的扫描和注册
  2. SqlSession规范化处理

实现

项目结构:

 └─src
   ├─main
   │ └─java
   │   └─com
   │     └─xbhog
   │       ├─binding
   │       │ ├─MapperProxy.java
   │       │ ├─MapperProxyFactory.java
   │       │ └─MapperRegistry.java
   │       └─session
   │         ├─DefaultSqlSession.java
   │         ├─DefaultSqlSessionFactory.java
   │         ├─SqlSession.java
   │         └─SqlSessionFactory.java
   └─test
     └─java
       └─com
         └─xbhog
           ├─AppTest.java
           └─IUserDao.java

项目类图

根据包路径实现接口的扫描和注册

可以通过自定义MapperRegistry这个类实现该功能,当然你也可以叫其他的名字(zhangsan、lisi);我们只需要将上一局的MapperProxyFactory封装到MapperRegistry,把需要扫描和注册的接口保存到Map中进行预处理,最后代理进行随时使用就可以了;铺垫结束,开始上代码。

先扫描包下所有的Class类,然后保存到Map中。

 package com.xbhog;
 ​
 import cn.hutool.core.lang.ClassScanner;
 ​
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 ​
 /**
  * @author xbhog
  * @describe: 接口注册器
  * @date 2024/2/25
  */
 public class MapperRegistry {
 ​
     private final Map<Class<?>,MapperProxyFactory<?>> interfaceMaps = new HashMap<>();
     public void addMapper(String packageName){
         Set<Class<?>> scanPackage = ClassScanner.scanPackage(packageName);
         scanPackage.forEach(clazz -> {
             addMappers(clazz);
        });
    }
 ​
     private void addMappers(Class<?> clazz) {
         if(clazz.isInterface()){
             //判断是否重复添加
             if(haveInterface(clazz)){
                 throw new RuntimeException("Type " + clazz + " is already known to the MapperRegistry.");
            }
        }
         // 注册映射器代理工厂
         interfaceMaps.put(clazz, new MapperProxyFactory<>(clazz));
    }
 ​
     private boolean haveInterface(Class<?> clazz) {
         return interfaceMaps.containsKey(clazz);
    }
 ​
 }

然后将上一局的接口和代理工厂操作封装进方法中。

 public <T> T getMapper(Class<T> type, SqlSession sqlSession){
     MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) interfaceMaps.get(type);
     if(Objects.isNull(mapperProxyFactory)){
         throw new RuntimeException("Type " + type + " is not known to the MapperRegistry.");
    }
     return (T)mapperProxyFactory.newInstance(sqlSession);
 }

SqlSession规范化处理

先定义一个执行Sql、获取映射器的标准接口:

 /**
  * @author xbhog
  * @describe: 定义简单的Mapper操作方法
  * @date 2024/2/25
  */
 public interface SqlSession {
 ​
     <T> T selectOne(String statement,Object parameter);
 ​
     /**
      *得到接口映射器
      * @param type 接口类型
      * @return
      */
     <T> T getMapper(Class<T> type);
 }

接口实现方式:

 package com.xbhog.session;
 ​
 import com.xbhog.binding.MapperRegistry;
 ​
 /**
  * @author xbhog
  * @describe:
  * @date 2024/2/25
  */
 public class DefaultSqlSession implements SqlSession{
 ​
     private MapperRegistry mapperRegistry;
 ​
     public DefaultSqlSession(MapperRegistry mapperRegistry) {
         this.mapperRegistry = mapperRegistry;
    }
 ​
     @Override
     public <T> T  selectOne(String statement,Object parameter) {
         return (T) ("你被代理了!" + "方法:" + statement + " 入参:" + parameter);
    }
 ​
     @Override
     public <T> T getMapper(Class<T> type) {
         return mapperRegistry.getMapper(type,this);
    }
 }

测试一下:

 package com.xbhog;
 ​
 import com.xbhog.binding.MapperProxyFactory;
 import com.xbhog.binding.MapperRegistry;
 import com.xbhog.session.DefaultSqlSession;
 import junit.framework.Test;
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
 ​
 import java.util.HashMap;
 import java.util.Map;
 ​
 /**
  * Unit test for simple App.
  */
 public class AppTest extends TestCase {
     /**
      * Rigourous Test :-)
      */
     public void testApp() {
         MapperRegistry mapperRegistry = new MapperRegistry();
         mapperRegistry.addMapper("com.xbhog");
         DefaultSqlSession sqlSession = new DefaultSqlSession(mapperRegistry);
         IUserDao user = sqlSession.getMapper(IUserDao.class);
         String userName = user.getUserName("xbhog");
         System.out.println("输出的信息:"+userName);
    }
 }

到这里其实已经可以满足需求了,但是看了下源码发现还是不行,它最外层又封装了一层代理工厂;应该是为了后续的代码扩展,简单工厂模式有助于代码的模块性和可维护性,功能上后续会有配置管理、资源管理、执行器选择和插件等需求;走一步看三步的老狐狸(┬┬﹏┬┬)。先抄作业。

 package com.xbhog.session;
 ​
 import com.xbhog.binding.MapperRegistry;
 ​
 /**
  * @author xbhog
  * @describe:
  * @date 2024/2/25
  */
 public class DefaultSqlSessionFactory implements SqlSessionFactory{
 ​
     private final MapperRegistry mapperRegistry;
 ​
     public DefaultSqlSessionFactory(MapperRegistry mapperRegistry) {
         this.mapperRegistry = mapperRegistry;
    }
 ​
     @Override
     public SqlSession openSession() {
         return new DefaultSqlSession(mapperRegistry);
    }
 }

测试

 package com.xbhog;
 ​
 import com.xbhog.binding.MapperProxyFactory;
 import com.xbhog.binding.MapperRegistry;
 import com.xbhog.session.DefaultSqlSession;
 import com.xbhog.session.DefaultSqlSessionFactory;
 import com.xbhog.session.SqlSession;
 import com.xbhog.session.SqlSessionFactory;
 import junit.framework.Test;
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
 ​
 import java.util.HashMap;
 import java.util.Map;
 ​
 /**
  * Unit test for simple App.
  */
 public class AppTest extends TestCase {
     /**
      * Rigourous Test :-)
      */
     public void testApp() {
         MapperRegistry mapperRegistry = new MapperRegistry();
         mapperRegistry.addMapper("com.xbhog");
         DefaultSqlSessionFactory sqlSessionFactory = new DefaultSqlSessionFactory(mapperRegistry);
         SqlSession sqlSession = sqlSessionFactory.openSession();
         IUserDao user = sqlSession.getMapper(IUserDao.class);
         String userName = user.getUserName("xbhog");
         System.out.println("输出的信息:"+userName);
    }
 }

总结

  1. What(什么)
  • MapperRegistry是一个注册表,用于存储映射器接口(Mapper Interface)和对应的MapperProxyFactory。它负责管理映射器接口的生命周期。
  • DefaultSqlSessionFactory是MyBatis框架中用于创建SqlSession的工厂类。SqlSession是MyBatis的核心接口,用于执行SQL命令和获取映射结果。
  1. Why(为什么)
  • MapperRegistry的存在是为了确保映射器接口能够被MyBatis框架识别和管理,以便在运行时为这些接口创建代理对象,实现数据库操作的动态绑定。
  • DefaultSqlSessionFactory的目的是为了提供一个统一的入口点,用于创建和管理SqlSession实例。这样可以保证SqlSession的创建和关闭遵循统一的规范,同时提供了会话管理的能力。
  1. Who(谁)
  • MapperRegistry的使用者是MyBatis框架自身,它内部使用MapperRegistry来处理映射器接口的注册和代理对象的创建。
  • DefaultSqlSessionFactory的使用者是应用程序的开发者,他们通过SqlSessionFactory来获取SqlSession实例,进而执行数据库操作。
  1. Where(在哪里)
  • MapperRegistry是MyBatis框架的一部分,通常在MyBatis配置初始化时创建,并在整个应用程序的生命周期中存在。
  • DefaultSqlSessionFactory通常在应用程序启动时创建,并保存在一个全局的变量中,以便在需要时获取SqlSession实例。
  1. When(何时)
  • MapperRegistry的注册发生在MyBatis应用程序启动时,特别是在构建SqlSessionFactory的过程中。
  • DefaultSqlSessionFactory的创建也是在应用程序启动时,通常是在初始化阶段,用于后续的数据库操作。
  1. How(如何)
  • MapperRegistry通过扫描指定包下的映射器接口,并将它们与对应的MapperProxyFactory关联起来。当需要执行映射器接口中的方法时,MapperRegistry会使用MapperProxyFactory来创建一个MapperProxy代理对象。
  • DefaultSqlSessionFactory通过解析MyBatis的配置文件(如mybatis-config.xml,下一节的操作)来创建。它提供了openSession()方法,用于创建SqlSession实例。开发者可以通过SqlSession实例来执行映射器接口中定义的数据库操作。

需要注意的是:通过这两节可以看到mybatis中运用了大量的工厂模式;对外提供统一的方法,屏蔽细节以及上下文的关联关系,最终目的服务于用户,简化使用。

参考

https://mp.weixin.qq.com/s/o6lnWJqU_6FNO8HpxAs9gA

ChatGPT问答

【简写Mybatis-02】注册机的实现以及SqlSession处理的更多相关文章

  1. BurpSuite 1.7.32 Cracked 破解版[注册机]下载【无后门版】

    首先看一下我的注册后的: 注册机的使用也很简单,首先打开burp-loader-keygen.jar文件,然后随便填写license text,比如我填写的是:mrxn.net效果如下图: 然后点击m ...

  2. PostSharp 4.0注册机实现过程

    PostSharp是基于.NET平台设计的比较强调易学易用的AOP框架. 什么是AOP? http://wayfarer.cnblogs.com/articles/241024.html 新版的已失效 ...

  3. Webstorm 10 for mac osx 注册机,序列号,kegen

    小菜最近get到mac体验机会,早就耳闻mac非常适合做开发,于是迫不及待的安装各种开发工具,不知不觉,轮到前端开发神器webstorm了,看了一下官网的价格,心拔凉拔凉的. 果断搜索注册机,搜到的结 ...

  4. Flash Builder 4.7 注册机完美激活方法

    Flash Builder 4.7 破解注册方法目前较为通用的三种方法: 第一种:三步修改配置文件方法,这种有开发者反应这种方法在升级和创建纯 AS 项目时会存在问题,但我懒的去试这种方法的主要原因是 ...

  5. 转:Autodesk 2017软件下载+注册机+破解方法(持续更新)

    转载自http://blog.sina.com.cn/s/blog_710225790102w03e.html Autodesk 2017安装步骤: 安装Autodesk 2017相关软件 使用序列号 ...

  6. UltraEdit 注册机使用说明

    请断开网络连接(或直接拔掉网线)后执行: 安装完成后,点击弹出界面的“注册”按钮,然后直接点击“激活”,此时UltraEdit检测到网络断开则弹出界面提示“脱机激活”,此时启动注册机,并将UltraE ...

  7. 【转】破解Source Insight 3.5.0072过程 附:安装软件+注册机

    转载地址:http://blog.csdn.net/qs_hud/article/details/8884867 注册机及软件下载地址:http://download.csdn.net/detail/ ...

  8. HTTP抓包神器HTTP Analyzer V7 Build7.5.4汉化+注册机

    原版安装包.汉化文件.注册机下载:http://pan.baidu.com/s/1bMv1Si 密码:cqq1 一.安装:下载并安装英文原版  下载页面:http://www.ieinspector. ...

  9. ERWin 7.2下载安装及注册机

    ERWin 7.2下载安装及注册机   ERWin 7.2 下载地址: ftp://ftp.ca.com/CAproducts/erwin/ServicePacks/AFEDM72-b1644.exe ...

  10. C#:注册机的实现【提供源代码下载】

    代码下载 C#软件注册机 软件运行结果 参考文章 http://www.cnblogs.com/hanzhaoxin/archive/2013/01/04/2844191.html

随机推荐

  1. Flink 助力美团数仓增量生产

    简介: 本文由美团研究员.实时计算负责人鞠大升分享,主要介绍 Flink 助力美团数仓增量生产的应用实践.内容包括:1.数仓增量生产:2.流式数据集成:3.流式数据处理:4.流式 OLAP 应用:5. ...

  2. eBPF技术应用云原生网络实践系列之基于socket的service | 龙蜥技术

    ​简介:如何使用 socket eBPF进一步提升Service 网络的转发性能? ​ 背景介绍 Kubernetes 中的网络功能,主要包括 POD 网络,service 网络和网络策略组成.其中 ...

  3. 智能数据构建与管理平台Dataphin的前世今生:缘起

    简介: 阿里巴巴提出的OneData方法论帮助企业捋清了数据全生命周期的管理思路,更将其植入到产品Dataphin(智能数据构建与管理)中,通过阿里云为企业提供服务. Dataphin 智能数据构建与 ...

  4. dotnet 构建还原失败 NuGet.targets 错误可能原因

    我在一次断电关机之后,发现我所有的项目都构建不通过了,提示在 NuGet.targets 文件的第 130 行错误.原因就是存在有某个被项目引用的 NuGet 包被损坏,在进行 NuGet 还原时读取 ...

  5. netcore热插拔dll

    项目中有有些场景用到反射挺多的,用到了反射就离不开dll的加载.此demo适用于通过反射dll运行项目中加载和删除,不影响项目. ConsoleApp: 1 using AppClassLibrary ...

  6. Typecho博客网站迁移:MySQL ➡️ MarialDB

    目录 1. 引言 2. Typecho的自定义配置迁移 3. 数据库迁移:MySQL- > MarialDB 3.1 在原服务器中备份并导出数据库文件 3.2 将"backupdb.s ...

  7. NASM中的ALIGN ALIGNB SECTALIGN

    ALIGN与ALIGNB NASM中的ALIGN与ALIGNB是用来字节对齐的,它们接收2个参数,第一个参数是必须的,表示对齐的字节数(必须是2的幂),第二个参数是可选的,表示为了对齐而进行填充的内容 ...

  8. 密码学—Vigenere加密Python程序

    文章目录 维吉尼亚加密 加密算法 解密算法 注意事项 维吉尼亚加密 古典密码,属于多表加密. 怎么就是多表了? 维吉尼亚密码的加密算法实质是凯撒密码,因为他是先分好小组,然后用密钥串对应着分好组的每一 ...

  9. C语言:快速排序(详解)

    快速排序采用的是两头对比交换 http://t.csdn.cn/TXcAK 上面这个连接大家可以点进去看看博客李小白大大的图文解释,我觉得这个是对我启发比较大的,对刚接触快速排序的人来说非常友好,很快 ...

  10. Ubuntu Snap 简述

    Ubuntu Snaps Ubuntu Snaps 是 Ubuntu 的母公司 Canonical 于 2016 年 4 月发布 Ubuntu16.04 LTS(LongTermSupport,长期支 ...