1.简介
MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
这些类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 的发行包中的源代码。 假设你想做的不仅仅是监控方法的调用,那么你应该很好的了解正在重写的方法的行为。 因为如果在试图修改或重写已有方法的行为的时候,你很可能在破坏 MyBatis 的核心模块。 这些都是更低层的类和方法,所以使用插件的时候要特别当心。
1.1实现
1)实现 Interceptor 接口,通过@Intercepts指定拦截位置
@Intercepts({@Signature( type= Executor.class, method = "update", args = {MappedStatement.class,Object.class})}) public class ExamplePlugin implements Interceptor { public Object intercept(Invocation invocation) throws Throwable { return invocation.proceed(); } public Object plugin(Object target) { return Plugin.wrap(target, this); } public void setProperties(Properties properties) { } }
2)配置mybatis-config.xml
<plugins> <plugin interceptor="org.mybatis.example.ExamplePlugin"> <property name="someProperty" value="100"/> </plugin> </plugins>
2.实例
对StatementHandler.query方法进行拦截,记录慢SQL
package com.siyuan.dao.mybatis; import java.sql.Statement; import java.util.Properties; import org.apache.ibatis.executor.statement.StatementHandler; 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.session.ResultHandler; import org.apache.log4j.Logger; @Intercepts(@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class })) public class SqlStatisticInterceptor implements Interceptor { private static final Logger LOGGER = Logger.getLogger(SqlStatisticInterceptor.class); // 慢SQL阀值 private int slowSQLThreshold = 3000; @Override public Object intercept(Invocation invocation) throws Throwable { long start = System.currentTimeMillis(); Object result = invocation.proceed(); long timeSpent = System.currentTimeMillis() - start; StatementHandler handler = (StatementHandler) invocation.getTarget(); String sql = handler.getBoundSql().getSql().trim(); LOGGER.debug("spent [" + timeSpent + "]ms for :\n" + sql); if (timeSpent >= slowSQLThreshold) { LOGGER.warn("slow sql which costs [" + timeSpent + "]ms has been found:\n" + sql); } return result; } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { if (properties.get("slowSQLThreshold") == null) { return; } this.slowSQLThreshold = Integer.parseInt((String) properties.get("slowSQLThreshold")); } }
2) mybatis-config.xml
扫描二维码关注公众号,回复:
485559 查看本文章
<plugin interceptor="com.qfang.dao.mybatis.SqlStatisticInterceptor"> <property name="slowSQLThreshold" value="1000"/> </plugin>
3.原理
1)Interceptor.plugin方法将在创建Executor,ParameterHandler,ResultSetHandler,StatementHandler实例时被调用替代mybatis框架默认创建的实例
2)Plugin实现InvocationHandler,wrap方法通过Proxy创建Executor,ParameterHandler,ResultSetHandler,StatementHandler实例的代理类
public static Object wrap(Object target, Interceptor interceptor) { Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor); Class<?> type = target.getClass(); Class<?>[] interfaces = getAllInterfaces(type, signatureMap); if (interfaces.length > 0) { return Proxy.newProxyInstance( type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap)); } return target; }
4.参考资料
http://www.mybatis.org/mybatis-3/zh/configuration.html#plugins