• Mybatis,自定义Mybatis拦截器与Plugin


    上一篇:Mybatis,动态代理CRUD源码分析

    目录

    1. 引言

    2. 自定义插件的编写逻辑:根据Mybatis规则 编写一个拦截器,在拦截器内部加入自定义增强功能

    2.1 编写拦截器

    2.2 拦截器还要配置到mybatis里面,这里使用注解@Intercepts

    2.3 在mybatis-config.xml文件中配置

     2.4 测试

     3. 配置多个拦截器

    4. 拦截器的作用

    5. 修改参数

    5.1 写拦截器

    完整MyInterceptor



    1. 引言

    上一篇中的Mybatis底层的四个处理器:StatementHandler 、ParameterHandler、ResultSetHandler、 TypeHandler

    插件也涉及到4个核心对象StatementHandler 、ParameterHandler、ResultSetHandler、Executor

    回顾mybatis动态代理对象进行增删改查操作

     mapper.queryStudentById()方法添加断点,调试进入方法内部

    调用了invoke()方法,

     进入execute()方法

     进入selectOne()方法

     进入selectList()方法

     进入executor.query()方法

    进入delegate.query()方法

     进入queryFromDatabase()方法

     进入doQuery()方法,在该方法可以看到我们的核心对象:StatementHandler

     进入newStatementHandler(),把处理器statementHandlerinterceptorChain.pluginAll(),该方法增强处理器statementHandler

    拦截器类似于如下逻辑:

    进入interceptorChain.pluginAll();

     可以看到拦截器Interceptor接口在org.apache.ibatis.plugin包下

     上诉拦截器,4个核心对象StatementHandler 、ParameterHandler、ResultSetHandler、Executor)都有

     四大核心对象:都涉及到了拦截器 用于增强 ,四大核心对象都包含了 该增强操作

    2. 自定义插件的编写逻辑:根据Mybatis规则 编写一个拦截器,在拦截器内部加入自定义增强功能

            自定义插件编写步骤:

    2.1 编写拦截器

     实现刚刚提到的拦截器:Interceptor接口,注意在org.apache.ibatis.plugin接口中:

     

     

    可以看到interceptor接口有3个方法:intercepted()、plugin()、setProperties()。

     1. 先来看intercept()方法的放行方法:invoccation.proceed()

     

     2.  再来看plugin()方法

    plugin()方法将拦截器中定义的增强功能和4大核心对象封装成一个整体

     3. 最后setProperties()方法

    2.2 拦截器还要配置到mybatis里面,这里使用注解@Intercepts

    @Intercepts注解中使用{}添加@Signature注解

    拦截器可以拦截4大核心对象(StatementHandler、ParameterHandler、ResultSetHandler、Execute)其中一个

    通过type属性可以配置

     这里我们拦截StatementHandler的query()方法

     拦截上面的query(Statement var1,ResultHandler var2)方法

    上面代码args的值给错了,第二个参数应该是ResultHandler类型,在org.apache.ibatis.session.ResultHandler包下

     

     完整代码:

    1. package com.lyx.mybatis.interceptors;
    2. import org.apache.ibatis.executor.statement.StatementHandler;
    3. import org.apache.ibatis.plugin.*;
    4. import org.apache.ibatis.session.ResultHandler;
    5. import java.sql.Statement;
    6. import java.util.Properties;
    7. @Intercepts({
    8. @Signature(type = StatementHandler.class,
    9. method = "query",
    10. args = {Statement.class, ResultHandler.class})
    11. })
    12. public class MyInterceptor implements Interceptor {
    13. @Override
    14. public Object intercept(Invocation invocation) throws Throwable {
    15. System.out.println("这是一个拦截方法");
    16. Object proceed = invocation.proceed();
    17. System.out.println(proceed);
    18. return proceed;
    19. }
    20. //plugin()方法将拦截器中定义的增强功能和4大核心对象封装成一个整体
    21. @Override
    22. public Object plugin(Object o) {
    23. Object wrap = Plugin.wrap(o, this);
    24. return wrap;
    25. }
    26. //设置属性
    27. @Override
    28. public void setProperties(Properties properties) {
    29. System.out.println("设置属性"+properties);
    30. }
    31. }

    2.3 在mybatis-config.xml文件中配置

     

     2.4 测试

     黑色方框中为intercept()方法的输出内容,由于我的queryStudentById()方法到数据库里面查了2次数据,查询Student,再通过Student的外键查classroom表,所以intercept()方法执行两次。并打印Object proceed;

    刚刚plugin()方法没有打印信息,现在添加上,测试类改为UserTest,输出如下:可以看到plugin()方法执行了4次--->plugin()方法把拦截器和4大核心对象进行封装时会每一个都尝试封装一下

     3. 配置多个拦截器

     

     在mybatis-config.xml文件中配置:

    测试 

     分析:

     编写多个拦截器时,执行顺序和配置顺序一致

    4. 拦截器的作用

    例:

    select * from student  拦截器 ➔ select * from student limit 3,5(例如分页插件)

    select * from student  where Id = 1  拦截器 ➔ select * from student  where Id = 3

    为MyInterceptor类的intercept()方法添加如下

    1. Object target = invocation.getTarget();
    2. System.out.println("目标对象"+target);

    测试运行:

     看到target是RoutingStatementHandler类型

    再添加代码:

    1. MetaObject metaObject = SystemMetaObject.forObject(target);
    2. metaObject.getValue("parameterHandler.parameterObject");

    metaObject .getValue("xxx") 该方法可以获取RoutingStatementHandler 对象

    从而通过RoutingStatementHandler.getBoundSql()获取到XxxMapper.xml中的sql:

    metaObject.getValue("parameterHandler.boundsql.sql")

    通过RoutingStatementHandler.getParameterHandler()取到XxxMapper.xml中的sql的参数值:

    metaObject.getValue("parameterHandler.parameterObject");

     我们来获取一下queryUserById(12)方法的参数值:12

    执行:

     

     由此,我们可以通过拦截器去修改这个参数值

    5. 修改参数

    5.1 写拦截器

    添加注解

    @Intercepts({

            @Signature(

                    type =           ,

                    method =         ,

                    args = 

            )

    })

     修改参数代码如下:

    invocation.proceed();放行要最后写

     

     执行:

     改为11:

    测试成功 

    以上方法通过metaObject.setValue("parameterHandler.parameterObject",2);修改了参数

    也可以通过metaObject.setValue("parameterHandler.boundSql.sql","select * from..");

    完整MyInterceptor

    1. package com.lyx.mybatis.interceptors;
    2. import org.apache.ibatis.executor.statement.RoutingStatementHandler;
    3. import org.apache.ibatis.executor.statement.StatementHandler;
    4. import org.apache.ibatis.plugin.*;
    5. import org.apache.ibatis.reflection.MetaObject;
    6. import org.apache.ibatis.reflection.SystemMetaObject;
    7. import org.apache.ibatis.session.ResultHandler;
    8. import java.sql.Statement;
    9. import java.util.Properties;
    10. @Intercepts({
    11. @Signature(type = StatementHandler.class,
    12. method = "parameterize",
    13. args = Statement.class)
    14. })
    15. public class MyInterceptor implements Interceptor {
    16. @Override
    17. public Object intercept(Invocation invocation) throws Throwable {
    18. Object target = invocation.getTarget();
    19. MetaObject metaObject = SystemMetaObject.forObject(target);
    20. Object value = metaObject.getValue("parameterHandler.parameterObject");
    21. System.out.println("方法的参数值为:"+value);
    22. metaObject.setValue("parameterHandler.parameterObject",11);
    23. Object value2 = metaObject.getValue("parameterHandler.parameterObject");
    24. System.out.println("修改后方法的参数值为:"+value2);
    25. Object proceed = invocation.proceed();
    26. System.out.println(proceed);
    27. return proceed;
    28. }
    29. @Override
    30. public Object plugin(Object o) {
    31. Object wrap = Plugin.wrap(o, this);
    32. System.out.println("这是plugin : " + wrap);
    33. return wrap;
    34. }
    35. @Override
    36. public void setProperties(Properties properties) {
    37. System.out.println("这是设置属性" + properties);
    38. }
    39. }

  • 相关阅读:
    网络安全:SQL盲注概述
    【操作系统】BIOS开机自检
    编译器一日一练(DIY系列之词法分析)
    android中使用opengl(.jni文件使用)
    计算机毕设项目论文介绍(Java智慧物业管理系统为例)
    解决中端投资痛点,“轻中端”能否抢占投资价值高地?
    香港科技大学广州|机器人与自主系统学域博士招生宣讲会—武汉大学专场!!!(暨全额奖学金政策)
    嵌入式笔试面试刷题(day12)
    @RabbitListener和@RabbitHandler的使用
    C++中的<string>头文件 和 <cstring>头文件简介
  • 原文地址:https://blog.csdn.net/m0_47010003/article/details/127347305