首页 > 其他分享 >Mybatis 插件的工作原理?

Mybatis 插件的工作原理?

时间:2024-12-29 17:27:45浏览次数:3  
标签:插件 拦截器 Object class method 源码 Mybatis 原理 public

 作者简介:大家好,我是码炫码哥,前中兴通讯、美团架构师,现任某互联网公司CTO,兼职码炫课堂主讲源码系列专题


代表作:《jdk源码&多线程&高并发》,《深入tomcat源码解析》,《深入netty源码解析》,《深入dubbo源码解析》,《深入springboot源码解析》,《深入spring源码解析》,《深入redis源码解析》等


联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬。码炫课堂的个人空间-码炫码哥个人主页-面试,源码等

回答

Mybatis 的运行涉及到 Executor、StatementHandler、ParameterHandler、ResultSetHandler 等组件,插件的工作原理就是在这些组件执行过程中,插入一些自定义的代码逻辑。

MyBatis 插件机制允许用户自定义拦截器(实现Interceptor接口),以在执行 SQL 的各个阶段进行额外的处理。

说一下 Mybatis 的工作原理?

实现机制

Mybatis 使用 JDK 动态代理,为目标对象生成代理对象。从而在目标对象方法调用时被拦截器拦截处理。

public class Plugin implements InvocationHandler {

  /**
  * 创建代理对象
  */
  public static Object wrap(Object target, Interceptor interceptor) {
    // 获取拦截器关注的类和方法签名的映射  
    Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
    Class<?> type = target.getClass();
    // 获取目标对象实现的所有接口
    Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
    // JDK 动态代理创建目标对象  
    if (interfaces.length > 0) {
      return Proxy.newProxyInstance(
          type.getClassLoader(),
          interfaces,
          new Plugin(target, interceptor, signatureMap));
    }
    return target;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      // 从签名 Map 获取方法  
      Set<Method> methods = signatureMap.get(method.getDeclaringClass());
      // 存在则执行拦截器逻辑  
      if (methods != null && methods.contains(method)) {
        return interceptor.intercept(new Invocation(target, method, args));
      }
      return method.invoke(target, args);
    } catch (Exception e) {
      throw ExceptionUtil.unwrapThrowable(e);
    }
  }

}

扩展

Mybatis 插件的实现步骤

  • 定义拦截器:实现Interceptor接口。
@Intercepts({
    @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class MyInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 添加自定义的拦截逻辑
        System.out.println("Before executing SQL");
        Object returnValue = invocation.proceed(); // 继续执行原方法
        System.out.println("After executing SQL");
        return returnValue;
    }

    @Override
    public Object plugin(Object target) {
        // 创建代理对象。
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 设置插件属性
    }
}

  • 配置拦截器:在 MyBatis 配置文件中注册拦截器。

方法一

<configuration>
    <plugins>
        <plugin interceptor="com.damingge.interceptor.MyInterceptor"/>
    </plugins>
</configuration>

方法二

@Configuration
public class MyBatisConfig {

    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        // 设置自定义插件
        Interceptor[] plugins = {new MyInterceptor()};
        sessionFactoryBean.setPlugins(plugins);
        return sessionFactoryBean.getObject();
    }
}

备注:在 MyBatis 中,支持多个拦截器。拦截器之间的执行顺序由它们在配置中的声明顺序决定。

  1. 拦截目标方法:在拦截器中定义要拦截的方法和逻辑。
@Intercepts({
    @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})

@Intercepts  @Signature 注解

  • type:拦截的对象类型。
  • method:拦截的方法名称。
  • args:方法的参数类型。

标签:插件,拦截器,Object,class,method,源码,Mybatis,原理,public
From: https://blog.csdn.net/smart_an/article/details/144807434

相关文章

  • 2024-11-28《关于mybatis创建的mapper映射路径不对导致的系列报错》
    关于mybatis创建的mapper映射路径不对导致的系列报错 今天在写mybatis项目的时候,使用注解发现无法使用别名,添加ResultMap的时候直接报错显示无法解析。经过百度了好久也是成功的发现了问题的所在,就是这个:这个路径创建的时候我以为创建的是分级目录,实际上创建成为了com.inn......
  • Hudi数据湖_数据写原理_COW和MOR表Upsert原理_Flink和Spark写入区别_Insert和Overwrit
    可以看到数据写操作,有三种方式upsert就是通过index索引来,对数据到底是insert还是update会做上标记,并且,只有索引到了数据才会update,所以是依赖index索引的.insert就是不停的插入数据,跳过了index,插入快,但是有重复数据,可能需要自己处理bulk_insert 写排序默认......
  • 如何在一台不能联网的电脑上的chrome浏览器上安装插件?
    gggggggggggggggggggggggpt要在无法联网的计算机上安装Chrome插件,你可以按照以下步骤操作:步骤1:下载插件的CRX文件在联网的计算机上打开Chrome浏览器并访问Chrome网上应用店。搜索并找到你需要安装的插件。使用一个Chrome扩展插件下载工具(如CRXDownloader,或使......
  • GitHub 汉化插件,GitHub 中文化界面安装全教程
    概述GitHub作为全球最大的代码托管平台,拥有庞大的用户群体。对于中文用户来说,如果能将GitHub界面汉化,将大大提高使用体验和工作效率。本文将详细介绍如何通过安装汉化插件,实现GitHub界面的中文化。感谢maboloshi作者的无私奉献.GitHub汉化插件,GitHub中文化界面安装......
  • uniapp不能直接修改props的数据原理浅析
    uniapp不能直接修改props的数据Avoidmutatingapropdirectlysincethevaluewillbeoverwrittenwhenevertheparentcomponentre-renders.Instead,useadataorcomputedpropertybasedontheprop'svalue.Propbeingmutated:"expectDeliveryAt"......
  • Ubuntu20.04安装Qt5.15.2并配置qml_ros_plugin插件
    安装QtQt老版本采用离线安装,新版本采用在线安装器安装,在官网安装速度很慢,一般在国内的源下载。在中科大源下载Qt在线安装器http://mirrors.ustc.edu.cn/qtproject/official_releases/online_installers/安装依赖sudoaptinstallgccg++makecmakebuild-essentiallibgl1-......
  • Yocto 项目中的交叉编译:原理与实例
    Yocto项目是一个强大的工具集,它专注于为嵌入式系统生成定制的Linux发行版。交叉编译在Yocto项目中扮演着核心角色,它使得开发者能够在功能强大的宿主机上构建适用于资源受限目标设备的软件系统。这篇文章将从运行原理、实际案例和工具链组成等角度全面解析Yocto项目中......
  • 掌握MyBatis:从入门到精通的全方位指南
    mysql缓存:根据sql语句进入缓存,如果sql语句多加一个空格就进入不到同一个缓存,另外数据库数据发生了更新,缓存中的数据不会同步。延迟加载:先查询基本信息,再查询其他信息(相亲网站),而不是一次就查询出来。mybatis的框架概述数据库厂商都会有自己的驱动包,上面一......
  • mybatis一对多collection select
     mybatis一对多collectionselect在MyBatis中,处理一对多关系时,通常会在映射文件中使用<collection>元素,并在其中嵌套一个<select>元素来实现对关联表的查询。这种方式允许你从一个表(称为“一”的一方)中查询数据,并同时获取与其关联的多个表(称为“多”的一方)中的数据......
  • Material Design风格纯js确认框和对话框插件
    material-modal是一款MaterialDesign风格纯js确认框和对话框插件。该插件通过简单的CSS和JavaScript代码来构建确认框和对话框,是替代浏览器原生确认框和对话框的不错选择。在线预览  下载  使用方法在页面中引入material-modal.css和material-modal.js文件。<linkr......