当你在使用 MyBatis 框架时,你可以创建一个拦截器来拦截 MyBatis 在执行 SQL 语句前后的一些操作,例如修改 SQL 语句、记录 SQL 执行时间等。在 MyBatis 中,拦截器使用注解 @Intercepts
来标记,而 @Signature
注解则用来标记要拦截的方法。
@Signature
注解中有三个属性:
type
:指定要拦截的接口或类,例如 Executor.class,StatementHandler.class 等;method
:指定要拦截的方法名,例如 update、query 等;args
:指定要拦截的方法的参数类型数组,例如 {MappedStatement.class, Object.class},表示要拦截的方法有两个参数,第一个参数的类型是 MappedStatement,第二个参数的类型是 Object。
当你使用了 @Signature
注解后,你就可以将拦截器应用到 MyBatis 的 SQL 执行过程中。在这个过程中,如果执行的方法名、参数类型和数量等与 @Signature
中定义的一致,那么拦截器就会被调用。
下面是一个使用 @Intercepts
和 @Signature
注解的例子:
@Intercepts({
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class MyInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 在执行 SQL 语句之前,可以修改 SQL 语句或者记录 SQL 执行时间等操作
Object result = invocation.proceed();
// 在执行 SQL 语句之后,可以对返回结果进行处理,例如加密数据等操作
return result;
}
}
在这个例子中,我们创建了一个拦截器 MyInterceptor,并使用 @Intercepts
注解标记。我们将要拦截的接口类型指定为 Executor.class,要拦截的方法名为 update,参数类型数组为 {MappedStatement.class, Object.class}。
这个拦截器会在执行 Executor 接口中的 update 方法之前和之后被调用,并可以在方法执行前后做一些额外的操作。
除了这个例子,MyBatis 的官方文档中也提供了其他的 @Signature
注解的使用例子,你可以查看这个链接:https://mybatis.org/mybatis-3/zh/configuration.html#plugins
在 MyBatis 中,MappedStatement
类型的参数代表了执行的 SQL 语句,它包含了 SQL 语句的 ID、参数类型、返回类型、SQL 语句字符串等信息。MappedStatement
参数可以通过 Invocation
对象的 getArgs()
方法获取到。
在上面的例子中,我们使用 @Signature
注解指定了拦截器要拦截的方法是 Executor.update(MappedStatement ms, Object parameter)
。其中,MappedStatement
类型的参数就是用来传递 SQL 语句信息的。
至于 Object
类型的参数,则是传递给 SQL 语句的参数对象,它可以是任何类型的 Java 对象。在执行 SQL 语句时,MyBatis 会根据 MappedStatement
中定义的参数类型来将 Object
类型的参数转换为对应的 SQL 参数。
总之,MappedStatement
类型的参数和 Object
类型的参数在执行 SQL 语句时都是必须的,它们分别代表了 SQL 语句信息和 SQL 参数。而在拦截器中,我们可以通过 Invocation
对象获取到这两个参数,并对它们进行处理。
MappedStatement
对象通常是 MyBatis 内部自动生成的,包含了 SQL 语句的 ID、参数类型、返回类型、SQL 语句字符串等信息。这个对象会在执行 SQL 语句时自动传入,我们不需要手动传入。
下面是 Executor
接口中 update
方法的源码:
javaCopy code
int update(MappedStatement ms, Object parameter) throws SQLException;
可以看到,在执行 update
方法时,需要传入 MappedStatement
和 Object
类型的参数。这些参数是由 MyBatis 内部调用时传入的。
在 MyBatis 的执行过程中,MappedStatement
对象是在 Configuration
类的 buildAllMappedStatements()
方法中生成的,而参数对象 parameter
则是在执行 SQL 语句时通过 BoundSql
对象与 MappedStatement
相关联生成的。
Mybatis源码学习推荐
- MyBatis 官方文档:官方文档中详细介绍了 MyBatis 的各个模块和功能,包括使用、配置、插件等方面,是入门和进阶的必备参考资料。
- MyBatis 源代码:MyBatis 是开源项目,源代码可以在官方 GitHub 上找到,可以通过阅读源代码深入了解 MyBatis 的实现原理。
- MyBatis 揭秘:这是一本 MyBatis 实现原理的书籍,作者是 MyBatis 的核心开发者之一,详细讲解了 MyBatis 的设计和实现,包括 SQL 解析、映射、缓存、事务等方面。
- 《深入浅出MyBatis技术原理与实战》:这是一本非常适合入门的 MyBatis 书籍,讲解了 MyBatis 的基本使用和实现原理,并提供了实例演示,非常适合初学者入门。
@Signature
注解中的 args
数组可以指定被拦截方法的参数类型,可以放任意类型,例如:int.class
、String.class
等。拦截器会根据指定的参数类型匹配方法的参数类型,只有匹配成功才会拦截该方法。
在 MyBatis 中,@Signature
注解中常用的参数类型除了 MappedStatement
和 Object
之外,还有:
ResultHandler.class
:结果处理器,用于处理查询结果,通常在查询大量数据时使用。RowBounds.class
:行分页限制器,用于控制查询的结果数量和偏移量,通常用于分页查询。CacheKey.class
和CacheValue.class
:用于缓存数据的键和值类型。
除此之外,还可以根据需要自定义参数类型,例如:
@Intercepts({
@Signature(type = Executor.class, method = "query", args = {
MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class
})
})
这里指定了被拦截的方法为 query
,参数类型包括 MappedStatement.class
、Object.class
、RowBounds.class
和 ResultHandler.class
,即查询方法的参数类型。
在 MyBatis 中,Interceptor
接口的 intercept
方法中的 Invocation
参数表示被拦截的方法调用,其中的 getArgs
方法返回了被拦截方法的参数列表,是一个数组。
因为在 @Signature
注解中我们指定了被拦截方法的参数类型为 {MappedStatement.class, Object.class}
,所以 getArgs()[0]
表示的是被拦截方法的第一个参数 MappedStatement
,getArgs()[1]
表示的是被拦截方法的第二个参数 Object
。
所以,invocation.getArgs()[1]
表示的是被拦截方法的第二个参数,即传入到 SQL 语句中的实际参数。在拦截器中,我们可以通过修改这个参数来改变执行 SQL 语句的行为,或者在执行 SQL 语句前后执行一些其他逻辑。