Mybatis-Interceptor参数_Invocation解析——公共字段填充设计思路&&阿里规约

一、iBatis中的Invocation结构分析

在iBatis(或MyBatis)的插件开发中,Invocation对象是拦截器(Interceptor)的核心参数,封装了目标方法的执行上下文。其getArgs()方法返回一个对象数组,包含了当前执行方法的所有参数。以下是对getArgs()数组中索引含义的详细说明:

1. getArgs()[0]MappedStatement对象
  • 作用MappedStatement是iBatis中描述SQL映射的核心类,包含了SQL语句、命令类型(SqlCommandType)、参数映射等信息。

  • 代码示例

    java 复制代码
    MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
    SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); // 获取SQL类型(INSERT/UPDATE等)
  • 意义 :通过索引0,可以判断当前执行的SQL操作类型(如INSERTSELECT),从而进行动态逻辑处理。

2. getArgs()[1]:方法参数对象
  • 作用 :表示当前SQL操作的参数对象。可能是单个实体对象(如BaseModel)、Map,或批量操作的集合。

  • 代码示例

    java 复制代码
    Object parameter = invocation.getArgs()[1];
    // 通过findDbObject提取数据库实体
    BaseModel dbObject = findDbObject(parameter);
  • 典型场景

    • 单条插入:参数为BaseModel实例。
    • 批量插入:参数可能是Map,其中包含list字段的集合。
3. getArgs()[2]RowBounds或参数配置
  • 作用 :在分页查询中,表示分页信息(如RowBounds)。但如果是非查询操作(如插入、更新),可能为null或其他配置对象。
  • 注意:在示例代码中未使用此索引,需根据具体场景判断其内容。

二、BaseModelinstanceof分开考虑的原因

findDbObject方法中,参数可能有两种形态:

  1. 直接传递的BaseModel实例parameterObj instanceof BaseModel

  2. 通过Map封装的参数 :常见于动态SQL或多参数场景,例如:

    java 复制代码
    Map<String, Object> params = new HashMap<>();
    params.put("user", userModel); // userModel是BaseModel的子类

分开处理的原因

  • 灵活性 :兼容不同参数传递方式。例如,批量插入可能通过Map封装list字段传递集合。
  • 防御性编程 :避免因参数类型不匹配导致的ClassCastException
  • 业务场景适配 :某些框架或代码规范要求参数必须通过Map传递键值对。

三、BaseModel的设计出发点

1. 公共字段统一管理
  • 背景 :阿里Java开发手册强制要求表包含idcreate_timeupdate_time字段。

  • 实现

    java 复制代码
    public class BaseModel implements Serializable {
        protected Date createTime;
        protected Date updateTime;
        // getters/setters省略
    }
  • 优点 :所有实体类继承BaseModel后,无需重复定义公共字段,减少冗余代码。

2. 拦截器统一处理逻辑
  • 场景 :在插入或更新时,自动填充createTimeupdateTime

  • 拦截器逻辑

    java 复制代码
    if (sqlCommandType == SqlCommandType.INSERT) {
        dbObject.setCreateTime(new Date());
    }
    dbObject.setUpdateTime(new Date());
  • 扩展性 :可在此拦截器中统一生成主键(如调用generatedKey方法)。

3. 序列化支持
  • BaseModel实现Serializable接口,便于缓存(如Redis)或远程传输(如RPC)。

四、代码逻辑详解

1. 主键生成逻辑
  • 单条插入 :直接调用generatedKey(dbObject)生成主键。

  • 批量插入 :遍历Map中的list字段,逐个生成主键:

    java 复制代码
    if (parameter instanceof HashMap) {
        Object list = ((Map)parameter).get("list");
        for (Object o : (ArrayList) list) {
            generatedKey((BaseModel) o);
        }
    }
2. 防御性检查
  • 跳过非插入操作

    java 复制代码
    if (SqlCommandType.INSERT != sqlCommandType) {
        return invocation.proceed();
    }
  • 空值处理 :若未找到BaseModel实例,直接放行原始逻辑。


五、总结

  • Invocation结构 :通过getArgs()获取SQL上下文、参数、分页信息,是插件开发的核心入口。
  • BaseModel设计:通过公共字段抽象和拦截器统一处理,实现代码复用和逻辑解耦。
  • 参数兼容性 :通过instanceof分场景处理,提高代码健壮性和扩展性。
相关推荐
weixin_985432113 小时前
Spring Boot 中的 @ConditionalOnBean 注解详解
java·spring boot·后端
猎人everest3 小时前
快速搭建运行Django第一个应用—投票
后端·python·django
啾啾Fun5 小时前
精粹汇总:大厂编程规范(持续更新)
后端·规范
yt948325 小时前
lua读取请求体
后端·python·flask
IT_10245 小时前
springboot从零入门之接口测试!
java·开发语言·spring boot·后端·spring·lua
汪子熙6 小时前
在 Word 里编写 Visual Basic 调用 DeepSeek API
后端·算法·架构
寻月隐君7 小时前
手把手教你用 Solana Token-2022 创建支持元数据的区块链代币
后端·web3·github
代码丰7 小时前
使用Spring Cloud Stream 模拟生产者消费者group destination的介绍(整合rabbitMQ)
java·分布式·后端·rabbitmq
烛阴7 小时前
Cheerio DOM操作深度指南:轻松玩转HTML元素操作
前端·javascript·后端
Hello.Reader8 小时前
在多云环境透析连接ngx_stream_proxy_protocol_vendor_module
后端·python·flask