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 小时前
每日八股——Redis(1)
数据库·经验分享·redis·后端·缓存
毕设源码-郭学长2 小时前
【开题答辩全过程】以 基于SpringBoot技术的美妆销售系统为例,包含答辩的问题和答案
java·spring boot·后端
追逐时光者2 小时前
精选 10 款 .NET 开源免费、功能强大的 Windows 效率软件
后端·.net
追逐时光者2 小时前
一款开源、免费的 WPF 自定义控件集
后端·.net
S***q3773 小时前
Spring Boot管理用户数据
java·spring boot·后端
毕设源码-郭学长3 小时前
【开题答辩全过程】以 基于SpringBoot框架的民俗文化交流与交易平台的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
l***21783 小时前
SpringBoot Maven快速上手
spring boot·后端·maven
f***14774 小时前
SpringBoot实战:高效实现API限流策略
java·spring boot·后端
计算机毕设VX:Fegn08954 小时前
计算机毕业设计|基于springboot + vue动物园管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计