简单了解mybatis拦截器实现原理及实例

这篇文章主要介绍了简单了解mybatis*实现原理及实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

例行惯例,先看些基本概念:

1 *的作用就是我们可以拦截某些方法的调用,在目标方法前后加上我们自己逻辑

2 Mybatis*设计的一个初衷是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑。

自定义*

* mybatis 自定义*

* 三步骤:

* 1 实现 {@link Interceptor} 接口

* 2 添加拦截注解 {@link Intercepts}

* 3 配置文件中添加*

* 1 实现 {@link Interceptor} 接口

* 具体作用可以看下面代码每个方法的注释

* 2 添加拦截注解 {@link Intercepts}

* mybatis *默认可拦截的类型只有四种,即四种接口类型 Executor、StatementHandler、ParameterHandler 和 ResultSetHandler

* 对于我们的自定义*必须使用 mybatis 提供的注解来指明我们要拦截的是四类中的哪一个类接口

* 具体规则如下:

* a:Intercepts *: 标识我的类是一个*

* b:Signature 署名: 则是指明我们的*需要拦截哪一个接口的哪一个方法

* type 对应四类接口中的某一个,比如是 Executor

* method 对应接口中的哪类方法,比如 Executor 的 update 方法

* args 对应接口中的哪一个方法,比如 Executor 中 query 因为重载原因,方法有多个,args 就是指明参数类型,从而确定是哪一个方法

* 3 配置文件中添加*

* *其实就是一个 plugin,在 mybatis 核心配置文件中我们需要配置我们的 plugin :

* plugin interceptor=”liu.york.mybatis.study.plugin.MyInterceptor”

* property name=”username” value=”LiuYork”/

* property name=”password” value=”123456″/

* /plugin

* *顺序

* 1 不同*顺序:

* Executor – ParameterHandler – StatementHandler – ResultSetHandler

* 2 对于同一个类型的*的不同对象拦截顺序:

* 在 mybatis 核心配置文件根据配置的位置,拦截顺序是 从上往下

@Intercepts({

@Signature(method = “update”, type = Executor.class, args = {MappedStatement.class, Object.class}),

@Signature(method = “query”, type = StatementHandler.class, args = {Statement.class, ResultHandler.class})

public class MyInterceptor implements Interceptor {

* 这个方法很好理解

* 作用只有一个:我们不是拦截方法吗,拦截之后我们要做什么事情呢?

* 这个方法里面就是我们要做的事情

* 解释这个方法前,我们一定要理解方法参数 {@link Invocation} 是个什么鬼?

* 1 我们知道,mybatis*默认只能拦截四种类型 Executor、StatementHandler、ParameterHandler 和 ResultSetHandler

* 2 不管是哪种代理,代理的目标对象就是我们要拦截对象,举例说明:

* 比如我们要拦截 {@link Executor#update(MappedStatement ms, Object parameter)} 方法,

* 那么 Invocation 就是这个对象,Invocation 里面有三个参数 target method args

* target 就是 Executor

* method 就是 update

* args 就是 MappedStatement ms, Object parameter

* 如果还是不能理解,我再举一个需求案例:看下面方法代码里面的需求

* 该方法在运行时调用

@Override

public Object intercept(Invocation invocation) throws Throwable {

* 需求:我们需要对所有更新操作前打印查询语句的 sql 日志

* 那我就可以让我们的自定义* MyInterceptor 拦截 Executor 的 update 方法,在 update 执行前打印sql日志

* 比如我们拦截点是 Executor 的 update 方法 : int update(MappedStatement ms, Object parameter)

* 那当我们日志打印成功之后,我们是不是还需要调用这个query方法呢,如何如调用呢?

* 所以就出现了 Invocation 对象,它这个时候其实就是一个 Executor,而且 method 对应的就是 query 方法,我们

* 想要调用这个方法,只需要执行 invocation.proceed()

/* 因为我拦截的就是Executor,所以我可以强转为 Executor,默认情况下,这个Executor 是个 SimpleExecutor */

Executor executor = (Executor)invocation.getTarget();

* Executor 的 update 方法里面有一个参数 MappedStatement,它是包含了 sql 语句的,所以我获取这个对象

* 以下是伪代码,思路:

* 1 通过反射从 Executor 对象中获取 MappedStatement 对象

* 2 从 MappedStatement 对象中获取 SqlSource 对象

* 3 然后从 SqlSource 对象中获取获取 BoundSql 对象

* 4 最后通过 BoundSql#getSql 方法获取 sql

MappedStatement mappedStatement = ReflectUtil.getMethodField(executor, MappedStatement.class);

SqlSource sqlSource = ReflectUtil.getField(mappedStatement, SqlSource.class);

BoundSql boundSql = sqlSource.getBoundSql(args);

String sql = boundSql.getSql();

logger.info(sql);

* 现在日志已经打印,需要调用目标对象的方法完成 update 操作

* 我们直接调用 invocation.proceed() 方法

* 进入源码其实就是一个常见的反射调用 method.invoke(target, args)

* target 对应 Executor对象

* method 对应 Executor的update方法

* args 对应 Executor的update方法的参数

return invocation.proceed();

* 这个方法也很好理解

* 作用就只有一个:那就是Mybatis在创建*代理时候会判断一次,当前这个类 MyInterceptor 到底需不需要生成一个代理进行拦截,

* 如果需要拦截,就生成一个代理对象,这个代理就是一个 {@link Plugin},它实现了jdk的动态代理接口 {@link InvocationHandler},

* 如果不需要代理,则直接返回目标对象本身

* Mybatis为什么会判断一次是否需要代理呢?

* 默认情况下,Mybatis只能拦截四种类型的接口:Executor、StatementHandler、ParameterHandler 和 ResultSetHandler

* 通过 {@link Intercepts} 和 {@link Signature} 两个注解[!–empirenews.page–]三个核心方法都加了详细的注释,而且结合案例需求说明问题

那么多文字不想行看,没关系有概括

总结:

1.在mybatis中可被拦截的类型有四种(按照拦截顺序):

Executor:拦截执行器的方法。

ParameterHandler:拦截参数的处理。

ResultHandler:拦截结果集的处理。

StatementHandler:拦截Sql语法构建的处理。

2.各个参数的含义:

@Intercepts:标识该类是一个*;

@Signature:指明自定义*需要拦截哪一个类型,哪一个方法;

2.1 type:对应四种类型中的一种;

2.2 method:对应接口中的哪类方法(因为可能存在重载方法);

2.3 args:对应哪一个方法;

不知道能否帮助你理解,我的表达能力有限~~~

接下来我们看看 Plugin 类

package org.apache.ibatis.plugin;

* Plugin 类其实就是一个代理类,因为它实现了jdk动态代理接口 InvocationHandler

* 我们核心只需要关注两个方法

* wrap:

* 如果看懂了代码案例1的例子,那么这个方法很理解,这个方法就是 mybatis 提供给开发人员使用的一个工具类方法,

* 目的就是帮助开发人员省略掉 反射解析注解 Intercepts 和 Signature,有兴趣的可以去看看源码 Plugin#getSignatureMap 方法

* invoke:

* 这个方法就是根据 wrap 方法的解析结果,判断当前*是否需要进行拦截,

* 如果需要拦截:将 目标对象+目标方法+目标参数 封装成一个 Invocation 对象,给我们自定义的* MyInterceptor 的 intercept 方法

* 这个时候就刚好对应上了上面案例1中对 intercept 方法的解释了,它就是我们要处理自己逻辑的方法,

* 处理好了之后是否需要调用目标对象的方法,比如上面说的 打印了sql语句,是否还要查询数据库呢?答案是肯定的

* 如果不需要拦截:则直接调用目标对象的方法

* 比如直接调用 Executor 的 update 方法进行更新数据库

class Plugin implements InvocationHandler {

public static Object wrap(Object target, Interceptor interceptor) {

// 省略

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

// 省略

}

贴一段网上的通用解释吧:

Plugin的wrap方法,它根据当前的Interceptor上面的注解定义哪些接口需要拦截,然后判断当前目标对象是否有实现对应需要拦截的接口,如果没有则返回目标对象本身,如果有则返回一个代理对象。而这个代理对象的InvocationHandler正是一个Plugin。所以当目标对象在执行接口方法时,如果是通过代理对象执行的,则会调用对应InvocationHandler的invoke方法,也就是Plugin的invoke方法。

所以接着我们来看一下该invoke方法的内容。这里invoke方法的逻辑是:如果当前执行的方法是定义好的需要拦截的方法,则把目标对象、要执行的方法以及方法参数封装成一个Invocation对象,再把封装好的Invocation作为参数传递给当前*的intercept方法。如果不需要拦截,则直接调用当前的方法。Invocation中定义了定义了一个proceed方法,其逻辑就是调用当前方法,所以如果在intercept中需要继续调用当前方法的话可以调用invocation的procced方法。

这就是Mybatis中实现Interceptor拦截的一个思想

文章转自:黎青松SEO博客

来源地址:http://www.alitaohuo.com/fuwuqi/yunwei/1716.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:SEO优化专员,转转请注明出处:https://www.chuangxiangniao.com/p/900392.html

(0)
上一篇 2025年1月4日 01:56:19
下一篇 2025年1月4日 01:56:45

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 美国又出了一个“斯诺登” 偷了50TB的机密情报

    美国国家安全局承包商的一名前任雇员8日被控窃取并私藏大量机密文件,目前面临20项刑事指控。 路透社援引美国政府官员的话报道,这可能是美国历史上规模最大的政府机密失窃事件。 私藏量惊人 涉案男子名为哈罗德·马丁,现年52岁,家住美国马里兰州,…

    编程技术 2025年1月4日
    100
  • Linux系统从零到高手的进阶心得

    初次了解到Linux系统还是在我初中的时候,那时候正是在一个中二年龄,喜欢看小说,对于小说中出现的明显的非现实场景感到十分钦佩、羡慕,并常常幻想自己也有小说主人公那样的本领。那正是在这样一个充满幻想的年纪,我看到了一本关于重生、关于黑客的小…

    编程技术 2025年1月4日
    100
  • 后HTTPS时代:网站身份认证比加密更重要

    HTTPS加密应用在过去两年间取得了惊人成果,全球互联网超50%的网站流量启用HTTPS加密。然而,100%的加密环境,就等于安全吗?借助免费DV SSL证书,越来越多的恶意软件、钓鱼网站转向100%加密,得以逃避安全工具检测、欺骗用户信任…

    编程技术 2025年1月4日
    100
  • 嵌入式培训费贵?华清远见鸡年大促现良机!

    3月8日,小编从国内知名的嵌入式培训机构——华清远见了解到,当前学习智能硬件开发的年轻人越来越多,当然绝大多数人依然选择了捷径,那就是参加相关的技术培训,以短期达到能从事相关的工作,同时实现自己的价值。 但是,想要真正学习这些IT界的热门课…

    编程技术 2025年1月4日
    100
  • 解密:迅雷会员是如何实现高速下载的?

    迅雷凭借强大的下载能力、良好的使用体验以及丰富的服务,成为我们的常用软件,其推出的增值服务“迅雷会员”,也受到很多雷友的欢迎。但很多人估计都不知道,迅雷会员是如何实现高速下载的。今天,小编就跟大家科普一下。 传统下载方式与迅雷下载 传统的下…

    编程技术 2025年1月4日
    100
  • 总结5条对学习Linux系统有帮助的经验心得

    在学习Linux的开始阶段,我跟大家一样因为没有一点基础,学起来有点吃力,当对Linux有了一定的认知,你就会不断调整你的学习方式方法。并且在学习Linux的时候,记得放下您之前的思维,带着一个“无知”的学习态度去接触Linux,不妨是个很…

    编程技术 2025年1月4日
    100
  • 【SSL证书】HTTP被打压,HTTPS将逆袭

    近日,Firefox 52发布,Firefox 52中仍然坚持以往的态度,打压不安全的HTTP页面,而这次Mozilla带给用户的是HTTP的不安全登陆表单,在任何HTTP页面中,一个全新的“不安全密码警告”将会在用户点击表单时,直接出现在…

    编程技术 2025年1月4日
    100
  • 400余份阿里珍贵技术资料限时免费下载(持续更新中)

    2017年,你是否有一个小目标,打算在新的一年事业更上一层楼、代码写的更优美、对互联网生态拥有更多宏观的战略性了解? 小编精心挑选2016云栖大会、历届在线技术峰会、云栖技术直播核心资料,只把最好的呈现给你!因为资料集合过于庞大,所以分批放…

    编程技术 2025年1月4日
    100
  • DWG文件怎么打开 DWG文件查看器最新版下载

    DWG是我们常用的一种图纸格式,如今DWG文件广泛的应用于各个领域。DWG文件怎么打开?不少小伙伴可能刚接触DWG文件,因此不知道如何打开DWG文件。通过这篇文章,小编就来给大家介绍下简单的DWG文件打开方法以及DWG文件查看器最新版下载。…

    编程技术 2025年1月4日
    100
  • web技术栈中不可或缺的Linux技术

    随着第三次信息浪潮的冲击,web技术在近年来可谓发生了天翻地覆的变革。从单向信息的web1.0时代,逐步过渡到信息和人交互的web2.0再到数据主动与人*的web3.0时代,这些成就无疑归功于Web技术的迅速发展。 Web技术最重要的载体便…

    编程技术 2025年1月4日
    100

发表回复

登录后才能评论

联系我们

156-6553-5169

在线咨询: QQ交谈

邮件:253000106@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

联系微信