源码级别解读 mybatis 插件

本文详细介绍了MyBatis框架及其插件机制的工作原理,包括如何利用插件增强SQL执行逻辑,例如防止SQL注入、分页等功能。通过具体实例展示了自定义拦截器的实现方法。

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

摘自官网。。

为什么要使用mybatis,相信看这篇文章的童鞋都有所了解,俺这里就多废话几句。在orm框架中,有轻量级的dbutils与mybatis,重量级的有hibernate。

为什么要选择mybatis呢?原因如下:

1.简单,这个无需我多废话。肯定的啊,使用过的童鞋都知道,在dao层定义一个接口,然后定义一个对应的xml(xml中namespace的值对应接口的全限定名就ok。因为mybatis是通过namespaceid去和接口类进行映射,然后使用动态代理创建接口类的实例方法,参见动态代理).

2.结果集映射,我认为这是mybatis做的最牛的一点,也是选择他最大的一个理由

3.完善的缓存机制(mybatis有1级缓存和2级缓存),1级缓存是基于会话的(Session),2级缓存是基于应用级别。这里不做过多阐述,有兴趣的可以参考文章 http://www.iteye.com/topic/1112327/

4.强大的插件机制。它可以在运行过程中动态的执行你自己的业务逻辑,比如防止sql注入,分页,sql日志打印,sql执行耗时等都可以在插件中做。真正实现了业务与功能分离。让你随行所欲的在飞dao层中增加任何你想做的事情。

好了。上面说了那么多好处,本文中会有点穿插,但重点是插件机制。废话不多说,我们开始缕一缕mybatis的流程。

输入图片说明

这是mybatis的一张架构图,从中我们可以看得出。应用程序去调用对应的db操作时会经历 配置->打开会话->在会话中执行相应的操作,同时会话中包含了jdbc的事务(对,没错。就是jdbc的事务)。那么我们可以看得出来,会话是核心。而配置是关键。

我们可以打开配置类看看,中间有很多属性。我们绝大多数都可以忽略,但是

输入图片说明

这个就是mybatis内部维护的拦截器链。我们在解析配置,初始化的时候会给xml中写入一个拦截器的类,他是从

Configuration.addInterceptor(Interceptor interceptor)

这个方法中写入。这一点对于本文来讲很重要,请大家牢记。

我们可以看看sqlsession的结构、

输入图片说明

可以看得出来,他有2个实现类(用过spring的童鞋应该知道,sqlsessionTemplate是spring对sqlsession的简单封装,这里不再赘述), 那么就剩下了DefaultSqlSession和SqlSessionManager这两个类。

那么我们可以做一个大胆的假设,mybatis他默认打开的是DefaultSqlSession(其实在源码中是的)。我们要构建一个sqlsession的时候会使用 SqlSessionFactoryBuilder 这个类,通过传递一个抽象的Reader对象(是不是很眼熟?这玩意就是IO流里的字节流基类), 通过这个玩意传一个xml文件进来

输入图片说明

然后去构建一个SqlSessionFactory对象。

输入图片说明

这里没什么稀奇的,无非就是把我们文件中的那些属性转移给这个Configuration类中,至于这个类里面具体有什么我就不带大家看了。我们继续看打开会话的流程

输入图片说明

到这里他的会话构建就出来了,有心的童鞋这里应该能看到了吧,我上面说的jdbc事务和DefaultSqlSession

ok,我们打开这个类看看,里面全是一些模板方法。俺这里就不一一赘述

输入图片说明

我们的重点是从 输入图片说明

执行器(我暂且叫他执行器,也比较形象)开始 输入图片说明

他这里就有好多个实现类了。老规矩。我就不带着大家找了,直接上图。默认的执行器类型是SimpleExecutor

输入图片说明

找到这里,我们就会发现,这就是它的增删改查了。老规矩,不赘述

继续深入,接下来是插件部分的重点了:

在开始之前我们需要介绍一下,它的拦截器可以作用于

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)

  • ParameterHandler (getParameterObject, setParameters)

  • ResultSetHandler (handleResultSets, handleOutputParameters)

  • StatementHandler (prepare, parameterize, batch, update, query)

这些范围。

输入图片说明

输入图片说明

我在上面说过,interceptorChain 这个东东很重要,这就是我们的拦截器链。我们可以看到他会使用pluginAll(Object target)这个方法将所有拦截器加到拦截器链中。

而拦截器类是这样的。

输入图片说明

如果我们需要实现一个自己的拦截器则需要实现这个接口中的方法。

其中

Object intercept(Invocation invocation) throws Throwable; // 这个方法是拦截器的业务方法
Object plugin(Object target); // 这个方法是对拦截器的包装, 如果不包装的话它是不会被加入到拦截器链中
void setProperties(Properties properties);// 这个方法是设置一些额外的属性

看明白这个之后我们自己手动去编写一个拦截器类

/**
 * @author Autorun
 * Created by Autorun on 2018/1/4.
 */@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class}) })
public class LogInterceptor implements Interceptor {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        return invocation.proceed();
    }    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }    @Override
    public void setProperties(Properties properties) {

    }
}

@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class}) })

这一行是标注要拦截哪个类上的方法,参数等。然后使用动态代理的invoke(Object obj, Object... args)方法,执行我们的逻辑

如果有多个拦截器则按照顺序(因为他内部是使用的ArrayList容器,有序可重复,大家都懂得)

具体执行的话是使用Plugin类中的Object invoke(Object proxy, Method method, Object[] args) throws Throwable 方法来做的。可以看得出来。它里面调用了我们编写的 Object intercept(Invocation invocation) throws Throwable;

之后我们需要把我们写的拦截器类注入到拦截器链中。

在mybatis的配置文件中加入

<!-- mybatis-config.xml --><plugins>  <!-- 类的全限定名 -->
  <plugin interceptor="org.mybatis.example.ExamplePlugin"> 
  </plugin></plugins>

使我们的拦截器生效。运行程序就会发现我们的业务在对应的范围生效了。

输入图片说明

转载于:https://my.oschina.net/u/3421984/blog/1611678

芋道源码是一个开源项目,它提供了基于工作流管理系统(BPM)的解决方案。工作流是业务流程管理中的核心概念,它定义了在企业运营中为了完成某一特定业务目标所必须的步骤、规则和角色。工作流管理系统则是一种软件工具,它通过自动化和监控业务流程来确保这些流程的顺利执行,从而提升效率和减少错误。 在这个特定的文件中,我们关注的是"初始化sql语句-mysql版本",这部分代码涉及到了在使用MySQL数据库时,如何初始化BPM工作流模块所需的数据库结构。初始化过程涉及到创建和配置数据库表,这些表通常是用来存储工作流的定义、任务、流程实例、历史记录和其他相关数据的。 根据提供的描述,这份初始化sql语句是针对使用最新jdk17版本代码的系统。JDK17是Java平台的开发工具包,它为Java应用程序提供运行环境。这表明芋道源码BPM工作流模块被设计为与较新的Java环境兼容,这意味着它能够利用最新的Java特性和性能提升。 文件中的biz_bpm.sql是压缩包中的唯一文件,它显然是一个SQL脚本文件。SQL(Structured Query Language)是一种用于管理和操作关系数据库的标准编程语言。该脚本文件包含了用于创建和初始化芋道源码BPM工作流模块所需数据库表的SQL命令。 具体而言,该文件可能包含创建表的语句,如"CREATE TABLE",以及为这些表插入初始数据的语句,如"INSERT INTO"。这些表可能包括任务表、用户表、角色表、工作流定义表等。它们共同构成了BPM工作流模块的基础数据结构。 这些表的创建和初始化是部署工作流管理系统时不可或缺的步骤。数据库表的设计对系统的性能和可扩展性至关重要。在设计这些表时,需要考虑到数据的一致性、完整性和优化查询性能等因素。 芋道源码BPM工作流模块的初始化sql语句是为在MySQL数据库中配置工作流管理系统而准备
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值