一、iBatis中的Invocation
结构分析
在iBatis(或MyBatis)的插件开发中,Invocation
对象是拦截器(Interceptor
)的核心参数,封装了目标方法的执行上下文。其getArgs()
方法返回一个对象数组,包含了当前执行方法的所有参数。以下是对getArgs()
数组中索引含义的详细说明:
1. getArgs()[0]
:MappedStatement
对象
-
作用 :
MappedStatement
是iBatis中描述SQL映射的核心类,包含了SQL语句、命令类型(SqlCommandType
)、参数映射等信息。 -
代码示例 :
javaMappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); // 获取SQL类型(INSERT/UPDATE等)
-
意义 :通过索引0,可以判断当前执行的SQL操作类型(如
INSERT
或SELECT
),从而进行动态逻辑处理。
2. getArgs()[1]
:方法参数对象
-
作用 :表示当前SQL操作的参数对象。可能是单个实体对象(如
BaseModel
)、Map
,或批量操作的集合。 -
代码示例 :
javaObject parameter = invocation.getArgs()[1]; // 通过findDbObject提取数据库实体 BaseModel dbObject = findDbObject(parameter);
-
典型场景 :
- 单条插入:参数为
BaseModel
实例。 - 批量插入:参数可能是
Map
,其中包含list
字段的集合。
- 单条插入:参数为
3. getArgs()[2]
:RowBounds
或参数配置
- 作用 :在分页查询中,表示分页信息(如
RowBounds
)。但如果是非查询操作(如插入、更新),可能为null
或其他配置对象。 - 注意:在示例代码中未使用此索引,需根据具体场景判断其内容。
二、BaseModel
与instanceof
分开考虑的原因
在findDbObject
方法中,参数可能有两种形态:
-
直接传递的
BaseModel
实例 :parameterObj instanceof BaseModel
。 -
通过
Map
封装的参数 :常见于动态SQL或多参数场景,例如:javaMap<String, Object> params = new HashMap<>(); params.put("user", userModel); // userModel是BaseModel的子类
分开处理的原因:
- 灵活性 :兼容不同参数传递方式。例如,批量插入可能通过
Map
封装list
字段传递集合。 - 防御性编程 :避免因参数类型不匹配导致的
ClassCastException
。 - 业务场景适配 :某些框架或代码规范要求参数必须通过
Map
传递键值对。
三、BaseModel
的设计出发点
1. 公共字段统一管理
-
背景 :阿里Java开发手册强制要求表包含
id
、create_time
、update_time
字段。 -
实现 :
javapublic class BaseModel implements Serializable { protected Date createTime; protected Date updateTime; // getters/setters省略 }
-
优点 :所有实体类继承
BaseModel
后,无需重复定义公共字段,减少冗余代码。
2. 拦截器统一处理逻辑
-
场景 :在插入或更新时,自动填充
createTime
和updateTime
。 -
拦截器逻辑 :
javaif (sqlCommandType == SqlCommandType.INSERT) { dbObject.setCreateTime(new Date()); } dbObject.setUpdateTime(new Date());
-
扩展性 :可在此拦截器中统一生成主键(如调用
generatedKey
方法)。
3. 序列化支持
BaseModel
实现Serializable
接口,便于缓存(如Redis)或远程传输(如RPC)。
四、代码逻辑详解
1. 主键生成逻辑
-
单条插入 :直接调用
generatedKey(dbObject)
生成主键。 -
批量插入 :遍历
Map
中的list
字段,逐个生成主键:javaif (parameter instanceof HashMap) { Object list = ((Map)parameter).get("list"); for (Object o : (ArrayList) list) { generatedKey((BaseModel) o); } }
2. 防御性检查
-
跳过非插入操作 :
javaif (SqlCommandType.INSERT != sqlCommandType) { return invocation.proceed(); }
-
空值处理 :若未找到
BaseModel
实例,直接放行原始逻辑。
五、总结
Invocation
结构 :通过getArgs()
获取SQL上下文、参数、分页信息,是插件开发的核心入口。BaseModel
设计:通过公共字段抽象和拦截器统一处理,实现代码复用和逻辑解耦。- 参数兼容性 :通过
instanceof
分场景处理,提高代码健壮性和扩展性。