Mybatis源码学习第七天(插件开发原理)
插件概述:
插件是用来改变或者扩展mybatis的原有功能,mybatis的插件就是通过继承Interceptor拦截器实现的,在没有完全理解插件之前j禁止使用插件对mybatis进行扩展,有可能会导致严重的问题;
mybatis中能使用插件进行拦截的接口和方法如下:
Executor(update,query,flushStatement,commit,rollback,getTransation,close,isClose);
StatementHandler(prepare,parameterize,batch,update,query);
ParameterHandler(getParameterObject,setParameters);
ResultSetHandler(handleResultSets.handleCursorResultSets,handleOutputParameters);
插件实现步骤:
1:实现Interceptor接口方法
2:确定拦截的签名
3:在配置文件中配置插件
4:运行测试用例
本来不打算写的,后来想想写一个吧;
先看一下接口;
1 /** 2 * Copyright 2009-2019 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package org.apache.ibatis.plugin; 17 18 import java.util.Properties; 19 20 /** 21 * @author Clinton Begin 22 */ 23 public interface Interceptor { 24 25 /** 26 * 执行拦截逻辑的方法 27 * @param invocation 28 * @return 29 * @throws Throwable 30 */ 31 Object intercept(Invocation invocation) throws Throwable; 32 33 /** 34 * 35 * @param target 被拦截的对象,他的作用就是给拦截的对象生成一个代理对象 36 * @return 37 */ 38 default Object plugin(Object target) { 39 return Plugin.wrap(target, this); 40 } 41 42 /** 43 * 读取 在plugin中设置的参数 44 * @param properties 45 */ 46 default void setProperties(Properties properties) { 47 // NOP 48 } 49 50 }
手写慢SQL插件拦截器
1 package org.apache.ibatis.plugin.impl; 2 3 import org.apache.ibatis.executor.statement.StatementHandler; 4 import org.apache.ibatis.logging.jdbc.PreparedStatementLogger; 5 import org.apache.ibatis.plugin.Interceptor; 6 import org.apache.ibatis.plugin.Intercepts; 7 import org.apache.ibatis.plugin.Invocation; 8 import org.apache.ibatis.plugin.Signature; 9 import org.apache.ibatis.reflection.MetaObject; 10 import org.apache.ibatis.reflection.SystemMetaObject; 11 import org.apache.ibatis.session.ResultHandler; 12 13 import java.sql.PreparedStatement; 14 import java.sql.Statement; 15 import java.util.Properties; 16 17 /** 18 * @Description 慢SQL查询日志拦截器 19 * @ClassName ThresholdInterceptor 20 * @Author mr.zhang 21 * @Date 2020/3/23 21:35 22 * @Version 1.0.0 23 **/ 24 25 /** 26 * 定义拦截位置 27 * 参数解释: 28 * type:拦截的类 29 * method:该类的那个方法 30 * args:该方法的参数 31 */ 32 @Intercepts({ 33 @Signature(type = StatementHandler.class, method = "query", args = {Statement.class,ResultHandler.class}) 34 }) 35 public class ThresholdInterceptor implements Interceptor { 36 37 // 时间阈值 38 private Long threshold; 39 40 @Override 41 public Object intercept(Invocation invocation) throws Throwable { 42 long begin = System.currentTimeMillis(); 43 Object proceed = invocation.proceed(); 44 long end = System.currentTimeMillis(); 45 long runTime = end - begin; 46 // 如果大于等于阈值那么记录慢SQL 47 if(runTime>=threshold){ 48 // 获取参数 49 Object[] args = invocation.getArgs(); 50 // 根据方法参数可得知第0个是Statement 51 Statement stmt = (Statement) args[0]; 52 // 通过反射转化为metaObject 53 MetaObject metaObject = SystemMetaObject.forObject(stmt); 54 // getValue("h")是因为在动态代理中存在的InvocationHandler就是h 55 // protected InvocationHandler h; 在Proxy类中定义的 在动态代理生成代理类时都会存在 56 PreparedStatementLogger preparedStatementLogger = (PreparedStatementLogger) metaObject.getValue("h"); 57 PreparedStatement preparedStatement = preparedStatementLogger.getPreparedStatement(); 58 System.out.println("Sql语句:“"+preparedStatement.toString()+"”执行时间为:"+runTime+"毫秒,已经超过阈值!"); 59 } 60 61 return proceed; 62 } 63 64 @Override 65 public void setProperties(Properties properties) { 66 this.threshold = Long.valueOf(properties.getProperty("threshold")); 67 } 68 }
如果需要使用在mybatis-config.xml 的plugins中配置就可以了,记得配置阈值哦;
作者:彼岸舞
时间:2020\03\23
内容关于:Mybatis
本文部分来源于网络,只做技术分享,一概不负任何责任