拦截器介绍
MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能。
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,query,commit,rollback等方法,还有其他接口的一些方法等。
总体概括为:
拦截执行器的方法
拦截参数的处理
拦截结果集的处理
拦截Sql语法构建的处理
拦截器使用
配置文件添加
? <plugins>
? ? <plugin interceptor="com.uv.interceptor.MybatisInterceptor">
? ? ? <property name="name" value="test"></property>
? ? </plugin>
? </plugins>
MybatisInterceptor
import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
?
/*
?* @author cs
?* @date 2018/10/4 18:16
?*
?*/
?
//拦截StatementHandler类中参数类型为Statement的 prepare 方法
//即拦截 Statement prepare(Connection var1, Integer var2) 方法
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class MybatisInterceptor implements Interceptor {
?
?
? ? @Override
? ? public Object intercept(Invocation invocation) throws Throwable {
?
? ? ? ? StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
? ? ? ? //通过MetaObject优雅访问对象的属性,这里是访问statementHandler的属性;:MetaObject是Mybatis提供的一个用于方便、
? ? ? ? //优雅访问对象属性的对象,通过它可以简化代码、不需要try/catch各种reflect异常,同时它支持对JavaBean、Collection、Map三种类型对象的操作。
? ? ? ? MetaObject metaObject = MetaObject
? ? ? ? ? ? .forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,
? ? ? ? ? ? ? ? new DefaultReflectorFactory());
? ? ? ? //先拦截到RoutingStatementHandler,里面有个StatementHandler类型的delegate变量,其实现类是BaseStatementHandler,然后就到BaseStatementHandler的成员变量mappedStatement
? ? ? ? MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
? ? ? ? //id为执行的mapper方法的全路径名,如com.uv.dao.UserMapper.insertUser
? ? ? ? String id = mappedStatement.getId();
? ? ? ? //sql语句类型 select、delete、insert、update
? ? ? ? String sqlCommandType = mappedStatement.getSqlCommandType().toString();
? ? ? ? //数据库连接信息
// ? ? ? ?Configuration configuration = mappedStatement.getConfiguration();
// ? ? ? ?ComboPooledDataSource dataSource = (ComboPooledDataSource)configuration.getEnvironment().getDataSource();
// ? ? ? ?dataSource.getJdbcUrl();
?
? ? ? ? BoundSql boundSql = statementHandler.getBoundSql();
? ? ? ? //获取到原始sql语句
? ? ? ? String sql = boundSql.getSql();
? ? ? ? String mSql = sql + " limit 2";
? ? ? ? //通过反射修改sql语句
? ? ? ? Field field = boundSql.getClass().getDeclaredField("sql");
? ? ? ? field.setAccessible(true);
? ? ? ? field.set(boundSql, mSql);
?
? ? ? ? return invocation.proceed();
? ? }
?
? ? @Override
? ? public Object plugin(Object target) {
? ? ? ? return Plugin.wrap(target, this);
? ? }
?
? ? @Override
? ? public void setProperties(Properties properties) {
? ? ? ? //此处可以接收到配置文件的property参数
? ? ? ? System.out.println(properties.getProperty("name"));
? ? }
?
}