1.0插件的概念
来自mybatis官方:http://www.mybatis.org/mybatis-3/zh/configuration.html#plugins
MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
他的本质就是一个拦截器,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法。比如Executor的update 方法不满足我们的要求 我们要在执行update方法之前加入逻辑
2.0 Interceptor接口
拦截器需要实现 Interceptor
Interceptor源码
package org.apache.ibatis.plugin;
import java.util.Properties;
public interface Interceptor {
Object intercept(Invocation var1) throws Throwable;
Object plugin(Object var1);
void setProperties(Properties var1);
}
plugin方法是拦截器用于封装目标对象的,通过该方法我们可以返回目标对象本身,也可以返回一个它的代理。当返回的是代理的时候我们可以对其中的方法进行拦截来调用intercept方法,当然也可以调用其他方法,setProperties方法是用于在Mybatis配置文件中指定一些属性的。
3.0代码实现
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import java.util.Properties;
//对于实现自己的Interceptor而言有两个很重要的注解,一个是@Intercepts,其值是一个@Signature数组。@Intercepts用于表明当前的对象是一个Interceptor,而@Signature则表明要拦截的接口、方法以及对应的参数类型。来看一个自定义的简单Interceptor:
@Intercepts({
@Signature(method = "update", type = Executor.class, args = {
MappedStatement.class, Object.class
})
})
public class MyInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("*****************************插件被执行***************************************");
return invocation.proceed();
}
@Override
public Object plugin(Object o) {
return Plugin.wrap(o,this);
}
@Override
public void setProperties(Properties properties) {
}
}
4.0使用方式
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="config.properties"/>
<plugins>
<plugin interceptor="com.hhz.util.MyInterceptor"></plugin>
</plugins>
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.hhz.dao"/>
</mappers>
</configuration>
5.0测试
@Test
public void save(){
User user = new User();
user.setId(6L);
user.setUsername("插件测试");
user.setAge(40);
user.setSex(Boolean.FALSE);
UserMapper dao = sqlSession.getMapper(UserMapper.class);
dao.save(user);
sqlSession.commit();
}
日志:
DEBUG] Checking to see if class com.hhz.dao.UserMapper matches criteria [is assignable to Object]
*****************************插件被执行***************************************
[DEBUG] Opening JDBC Connection
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
[DEBUG] Created connection 1714378342.
[DEBUG] Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@662f5666]
[DEBUG] ==> Preparing: insert into user values(?,?,?,?);
[DEBUG] ==> Parameters: 6(Long), 插件测试(String), 40(Integer), false(Boolean)
[DEBUG] <== Updates: 1