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分场景处理,提高代码健壮性和扩展性。
相关推荐
GoGeekBaird11 小时前
我开源了 BeeWeave,给 AI Agent 搭一个越用越懂你的知识创作台
后端·github
犀利豆14 小时前
AI in Harness(四)
人工智能·后端
Hui Baby14 小时前
Spring Security
java·后端·spring
逝水无殇15 小时前
C# 运算符重载详解
开发语言·后端·c#
苏三说技术15 小时前
2026编程圈很火的10个Skills
后端
用户83562907805115 小时前
使用 Python 自动化 Excel 公式和函数:完整指南
后端·python
编程(变成)小辣鸡16 小时前
Spring事务失效场景
java·后端·spring
PinkSun16 小时前
MySQL 建表报 1030,能查不能建,排查 1 小时发现是我自己改了一行权限
后端
无相求码17 小时前
为什么 printf 可以接受任意数量参数?变长参数的底层真相
后端
郡杰17 小时前
Boot:MP|测验|结果封装|异常处理|前后联调|拦截器
后端