• 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

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

  • 相关阅读:
    JAVA并发之ReentrantLock源码(一)
    java并发之线程池
    Quine--输出程序源码的程序(java)
    【leetcode】Weekly Contest 92
    【java集合类】ArrayList和LinkedList源码分析(jdk1.8)
    【leetcode】Weekly Contest 91
    牛客2018.6模拟考编程题
    MFC 完全自定义控件
    图形学中求平面方程系数以及法向量
    std::function解决函数重载绑定
  • 原文地址:https://www.cnblogs.com/flower-dance/p/12555774.html
Copyright © 2020-2023  润新知