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分场景处理,提高代码健壮性和扩展性。
相关推荐
Vitalia42 分钟前
从入门到精通Rust:资源库整理
开发语言·后端·rust
放羊郎43 分钟前
CUDA兼容NVIDA版本关系
开发语言·后端·rust
天上掉下来个程小白5 小时前
登录-10.Filter-登录校验过滤器
spring boot·后端·spring·filter·登录校验
SomeB1oody6 小时前
【Rust中级教程】2.8. API设计原则之灵活性(flexible) Pt.4:显式析构函数的问题及3种解决方案
开发语言·后端·性能优化·rust
Asthenia04128 小时前
基于 MyBatis PageHelper 自定义 PageUtil 的分页实践指南
后端
Hamm9 小时前
封装一个优雅的自定义的字典验证器,让API字典参数验证更湿滑
java·spring boot·后端
刘立军9 小时前
本地大模型编程实战(22)用langchain实现基于SQL数据构建问答系统(1)
人工智能·后端·llm
刘立军9 小时前
本地大模型编程实战(21)支持多参数检索的RAG(Retrieval Augmented Generation,检索增强生成)(5)
人工智能·后端·llm
m0_748250749 小时前
Spring Boot 多数据源解决方案:dynamic-datasource-spring-boot-starter 的奥秘(上)
java·spring boot·后端