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分场景处理,提高代码健壮性和扩展性。
相关推荐
淳于韻珊1 小时前
Java语言的散点图
开发语言·后端·golang
mmmayang3 小时前
Golang 项目平滑重启
开发语言·后端·golang
褚翾澜3 小时前
Go语言的可选链
开发语言·后端·golang
小诸葛的博客5 小时前
client-go如何监听自定义资源
开发语言·后端·golang
入 梦皆星河5 小时前
go原理刨析之channel
开发语言·后端·golang
Pandaconda5 小时前
【新人系列】Golang 入门(十二):指针和结构体 - 上
开发语言·后端·golang·go·指针·结构体·后端开发
6<75 小时前
【go】类型断言
开发语言·后端·golang
u0103731065 小时前
Django异步执行任务django-background-tasks
后端·python·django
hxung5 小时前
springboot项目中常用的工具类和api
数据库·spring boot·后端
唐人街都是苦瓜脸5 小时前
SpringBoot的简单介绍
java·spring boot·后端