非得让你会之MyBatis插件与Java动态代理

引言

咱们今天聊聊Java动态代理,这东西在开发中真的太常见了。比如Spring AOP、RPC,它们都离不开动态代理。然后,咱们再来说说MyBatis插件,这可是MyBatis框架中的一个超实用的功能,它就像是给MyBatis加了个“超能力”。

小黑今天就带大家深入浅出地理解这两个技术是怎么一回事,以及它们是怎么一起工作的。搞懂了这些,你写代码的时候会觉得轻松多了!

Java动态代理基础

首先,让咱们先弄明白什么是Java动态代理。简单来说,动态代理就是在程序运行时创建代理类,而不是在编译时。这样做的好处是什么呢?灵活性大大增强,你可以在运行时根据需要来动态地创建代理类和代理方法。

Java中有两种动态代理方式:JDK原生动态代理和CGLIB动态代理。JDK动态代理主要用的是java.lang.reflect.Proxy这个类,以及InvocationHandler这个接口。来,咱们看个例子:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class DynamicProxyExample {public interface Hello {void sayHello();}static class HelloImpl implements Hello {public void sayHello() {System.out.println("Hello, world!");}}static class DynamicProxyHandler implements InvocationHandler {private Object target;public DynamicProxyHandler(Object target) {this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Before method call");Object result = method.invoke(target, args);System.out.println("After method call");return result;}}public static void main(String[] args) {Hello hello = new HelloImpl();Hello proxyInstance = (Hello) Proxy.newProxyInstance(Hello.class.getClassLoader(),new Class[]{Hello.class},new DynamicProxyHandler(hello));proxyInstance.sayHello();}
}

这段代码展示了如何使用JDK动态代理。首先,小黑定义了一个简单的Hello接口和一个实现了这个接口的HelloImpl类。然后,用DynamicProxyHandler类来实现InvocationHandler,在这里咱们添加了方法调用前后的打印逻辑。最后,在main方法里,用Proxy.newProxyInstance方法创建了Hello接口的代理实例,并调用了sayHello方法。

看,是不是很简单?这就是JDK动态代理的魅力所在!

MyBatis框架概览

小黑们,咱们先来聊聊MyBatis。MyBatis,它可是Java界的老牌ORM框架了,主要用来处理数据库和对象之间的映射关系。简单地说,它就是帮咱们把编写的SQL语句映射成Java对象的操作。这样一来,咱们就不用手动去拼接SQL字符串,也不用处理繁琐的结果集映射了。

MyBatis的核心就是它的SqlSession。通过SqlSession,咱们可以执行定义好的SQL语句,进行数据的增删改查。使用起来非常方便,配置一个mapper文件,里面定义好SQL语句和返回类型,MyBatis就会自动帮咱们搞定大部分工作。

再来说说MyBatis的插件系统。MyBatis的插件系统是基于动态代理实现的。咱们可以在执行SQL之前或之后插入自己的逻辑,比如记录日志、测量执行时间等等。这个系统非常强大,因为它允许咱们自定义拦截规则,精确到某个Mapper的某个方法。

MyBatis插件与动态代理

好,现在咱们来深入一点,看看MyBatis插件是怎么跟Java动态代理扯上关系的。MyBatis的插件,本质上就是一个动态代理。在MyBatis中,咱们定义的每个Mapper接口,背后其实都是一个动态代理在工作。

这个代理的工作原理是这样的:当咱们调用Mapper接口的方法时,实际上是调用了一个代理对象的方法。这个代理对象会拦截这个调用,然后根据Mapper XML配置的SQL语句,执行相应的数据库操作。

那么,如何使用MyBatis插件来实现自定义逻辑呢?来看看这段代码:

import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Signature;@Intercepts({@Signature(type=Executor.class, method="update", args={MappedStatement.class, Object.class})
})
public class MyPlugin implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 在SQL执行前可以加入咱们的逻辑System.out.println("Before invocation");// 继续执行原方法Object returnObject = invocation.proceed();// 在SQL执行后可以加入咱们的逻辑System.out.println("After invocation");return returnObject;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {// 这里可以接收配置文件中的属性}
}

这段代码就定义了一个简单的MyBatis插件。咱们使用了@Intercepts@Signature注解来指定这个插件将拦截Executor的update方法。在intercept方法里,咱们可以在SQL执行前后加入自定义的逻辑。

通过这样的机制,MyBatis插件让数据库操作变得更加灵活,咱们可以轻松地实现各种自定义功能。

pisHJaT.png

实现自定义MyBatis插件

咱们来聊聊如何给MyBatis加个自定义插件。想要搞定这个,首先得明白MyBatis插件是怎么一回事。简单来说,MyBatis允许我们在操作数据库前后插入自己的逻辑,这就是插件的用武之地。我们得用到Java动态代理技术来实现它。

创建一个简单的MyBatis插件

小黑先给大家展示一个简单的例子。我们要做的是,每次执行SQL前打印一下SQL语句。看起来挺简单,但也足够展示插件的威力。

// 导入MyBatis相关类
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import java.util.Properties;public class SqlPrintPlugin implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {System.out.println("执行SQL前: " + invocation.getArgs()[0]);return invocation.proceed();}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {}
}
注册并使用插件

在MyBatis配置文件中注册这个插件,这样MyBatis就知道了我们有这么一个插件。

<plugins><plugin interceptor="SqlPrintPlugin"/>
</plugins>

优化和问题解决

1. 性能调优
  • 轻量化处理: 当咱们的插件逻辑太复杂时,会拖慢整个应用的速度。所以,务必保证逻辑简单明了,避免不必要的计算和资源消耗。
  • 利用缓存: 如果插件需要频繁读取数据库或调用外部服务,考虑引入缓存机制,减少重复的数据读取,提高性能。
2. 异步处理
  • 背景任务: 有些插件操作不需要即时完成,比如日志记录、数据分析等。这些可以通过异步方式进行,避免阻塞主线程。
3. 错误处理和日志
  • 健壮的错误处理: 确保你的插件能妥善处理异常情况,不让任何错误影响到主业务流程。
  • 详细的日志记录: 记录足够的日志对于问题定位和性能调优都至关重要。但别过头了,太多的日志也会影响性能。
4. 插件测试
  • 全面的单元测试: 通过单元测试确保插件的每个部分都能正确运行。
  • 集成测试: 在真实环境中测试插件,确保与其他组件的兼容性。
5. 配置灵活性
  • 提供配置选项: 允许用户根据需求调整插件的行为,增加插件的灵活性和适用范围。

总结

通过这篇博客,咱们一起探索了如何巧妙地运用Java动态代理来增强MyBatis的功能。

Java动态代理真的很强大。它不仅让代码更加灵活,还极大地提高了咱们的开发效率。通过动态代理,小黑演示了如何在运行时动态地处理接口方法的调用,实现了非侵入式的编程,这对于维护大型项目来说,简直是救星!

咱们深入MyBatis插件,看看它是怎样运用Java动态代理的。通过自定义插件,咱们能在MyBatis执行SQL前后插入自己的逻辑,这对于实现复杂的业务需求来说,简直太有用了。比如说,咱们可以在SQL执行前打印日志,或者在执行后做一些数据处理。

技术的学习是无止境的。Java动态代理和MyBatis插件只是冰山一角。通过实践和不断探索,咱们能够发现更多有趣的技术组合,创造出更加高效和强大的应用。希望大家能从这篇博客中获得灵感,将学到的知识运用到实际工作中去。加油,咱们一起进步!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/190956.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

『测试基础』| 如何理解测试用例管理和缺陷管理?

『测试管理攻略』| 如何理解测试用例管理和缺陷管理&#xff1f; 1 测试用例定义2 测试用例设计原则3 测试用例的评审4 测试如何维护&#xff1f;5 用例的作用6 用例管理工具7 缺陷关注的重点8 缺陷分析9 缺陷管理工具 1 测试用例定义 测试用例&#xff08;TestCase&#xff0…

西南科技大学(数据结构A)期末自测练习四

一、填空题&#xff08;每空1分&#xff0c;共10分&#xff09; 1、树最适合用来表示( C ) A.有序数据元素 B.无序数据元素 C.元素之间具有层次关系的数据 D.元素之间具有多对多关系的数据 2、根据二叉树的定义可知二叉树共有&#xff08; B&#xff09;种不同的基本形态…

react 面试题 50题 大公司常问的面试

1. 请解释 React 是什么以及它的主要特点。 2. 请解释 React 中的虚拟 DOM&#xff08;Virtual DOM&#xff09;以及它的工作原理。 3. 请解释 React 中的组件&#xff08;Components&#xff09;以及它们如何工作。 4. 请解释 React 中的生命周期方法&#xff08;Lifecycle Me…

Zabbix监控openstack系统资源

一、简介 随着信息技术的不断发展&#xff0c;作为基础平台,封闭架构带来不兼容性,无法支持异构虚拟机系统,也难以支撑开放合作的产业链需求。随着云计算时代的来临,虚拟化管理平台向开放平台架构转变,多种厂家的虚拟机可以在开放的平台架构下共存,不同的应用厂商可以基于开放…

12.1平衡树(splay),旋转操作及代码

平衡树 变量定义 tot表示结点数量&#xff0c;rt表示根的编号 v[i]表示结点i的权值 fa[i]表示结点i的父亲节点 chi[i][2]表示结点i的左右孩子 cnt[i]表示结点i的权值存在数量&#xff0c;如1123&#xff0c;v[3]1&#xff0c;则cnt[3]2;就是说i3的三号结点的权值为1&…

备忘录模式-C++实现

备忘录是一种行为型设计模式&#xff0c;它允许在不破坏封装性的前提下捕获和恢复一个对象的内部状态。它将对象的内部状态保存到备忘录对象中&#xff0c;并在需要的时候从备忘录中取出恢复状态&#xff0c;实现了状态的保存和恢复。 备忘录有以下三个角色&#xff1a; 1、发…

Mybatis-Plus条件构造器Wrapper

常用的两种条件构造器分别是 QueryWrapper 和 LambdaQueryWrapper QueryWrapper Autowiredprivate StudentMapper studentMapper;Testpublic void test() {//条件分页查询学生&#xff0c;性别为2&#xff08;代表女&#xff09;&#xff0c;年龄大于等于12的学生QueryWrapper&…

树和二叉树的基本概念和堆的实现

树的概念及结构 树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 1.有一个特殊的结点&#…

04-配置远程仓库的SSH免密登陆

配置SSH免密登录 配置步骤 创建好的远程仓库也可以使用SSH的方式进行访问,但如果没有配置公钥会有警告 第一步: 删除用户家目录下的.ssh目录,如果没有该目录或者该目录下已经有密钥了就不用执行该操作 #进入当前用户的家目录,删除.ssh 目录 LayneLAPTOP-Layne MINGW64 ~ $ r…

python datetime 获取特定一天的后一天或者后几天

这里写自定义目录标题 1 获取特定天的时间对象 具体时间格式参考&#xff1a;Python time strptime()和strftime()-CSDN博客 import datetimetimer datetime.datetime.strptime(date, "%Y-%m-%d")2 获取下一天或者【下x天】的数据并进行格式转换 # 下一天数据 ne…

基于SpringBoot+Vue的前后端分离的房屋租赁系统2

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 开发过程中&#xff0…

uniApp打包的手机app如果用户没开启通知权限、引导用户开启

封装一个setPermissions.js文件 /*** 如果用户没开启通知权限、引导用户开启 */ export function setPermissions() {// #ifdef APP-PLUS if (plus.os.name Android) {var main plus.android.runtimeMainActivity();var pkName main.getPackageName();var uid main.getApp…

基于WebSocket实现客户聊天室

目录 一、实现聊天室原理 二、聊天室前端代码 三、聊天室后端代码&#xff08;重点&#xff09; 四、聊天室实现效果展示 一、实现聊天室原理 1.1 介绍websocket协议 websocket是一种通信协议&#xff0c;再通过websocket实现弹幕聊天室时候&#xff0c;实现原理是客户端首…

Dynamo初学配置

配置参考 视频参考 Dynamo之Python编程视频教学_dynamo python-CSDN博客 升级Python3参考【需要Revit2020版本&#xff0c;2019版本不适用】 Dynamo 升级使用 Python3教程_dynamo升级找不到cpython-CSDN博客 Dynamo数据淘金——01//升级配置Dynamo - 哔哩哔哩 dynamo中pyt…

【动态规划】LeetCode-931.下降路径最小和

&#x1f388;算法那些事专栏说明&#xff1a;这是一个记录刷题日常的专栏&#xff0c;每个文章标题前都会写明这道题使用的算法。专栏每日计划至少更新1道题目&#xff0c;在这立下Flag&#x1f6a9; &#x1f3e0;个人主页&#xff1a;Jammingpro &#x1f4d5;专栏链接&…

jira配置https访问-running-jira-applications-over-ssl-or-https

命令行配置步骤 Command line installation 过程说明&#xff1a; 创建存放证书的本地秘钥库keystore文件jira.jks&#xff0c;生成证书签名请求文件csr.txt或者jira.csr&#xff1b; 自签名&#xff0c;生成密钥和根证书&#xff1b; 使用根证书ca.crt对csr.txt进行签名&…

求二叉树叶子结点个数或求二叉树非叶子结点个数。

题目描述&#xff1a;求二叉树叶子结点个数。 分析&#xff1a; 考虑递归和非递归两种方法 <1>递归 int Leaves(BiTree T){if(T NULL)return 0;if(T->lchild NULL && T->rchild NULL)return 1;elsereturn Leaves(T->lchild) Leaves(T->rchild…

服务器基础知识

服务器被誉为互联网之魂。我第一次见到服务器是在学校图书馆&#xff0c;是一种机架式服务器&#xff0c;第二次见到服务器是在公司机房。本期文章是对服务器进行大盘点和梳理&#xff0c;会介绍我拆装服务器过程&#xff0c;从中的学习感悟。 图片来自 Pexels 01 服务器 服务…

TCP网络常见名词

1、MAC地址 用来识别同一链路中不同的计算机。 2、IP地址 用来识别TCP/IP网络中互连的主机和路由器。 3、端口号 用来识别同一台计算机中进行通信的不同应用程序。 1&#xff09;端口号如何确定 <1>标准既定的端口号 它是指每个应用程序都有其指定的端口号。例如…

vue---消息订阅与发布(pubsub)

一种组件间通信的方式&#xff0c;适用于任意组件间通信 使用步骤&#xff1a; 安装pubsub&#xff1a;npm i pubsub-js 引入&#xff1a;import pubsub from pubsub-js 接收数据&#xff1a;A组件想接收数据&#xff0c;则在A组件中订阅消息&#xff0c;订阅的回调留在A组…