Mybatis源码学习第七天(插件开发原理)

时间:2022-07-26
本文章向大家介绍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中配置就可以了,记得配置阈值哦;

作者:彼岸舞

时间:2020323

内容关于:Mybatis

本文部分来源于网络,只做技术分享,一概不负任何责任