mybatis 插件机制

mybatis 4大插件

mybatis 插件机制_第1张图片

分页插件功能设计

mybatis 插件机制_第2张图片
mybatis 插件机制_第3张图片

代码


    
      
    
  
package com.wfg.interceptor;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.Properties;

/**
 * @author wufagang
 * @description
 * @date 2021年10月24日 15:14
 */
@Intercepts(@Signature(type = StatementHandler.class,method = "prepare",args = {Connection.class,Integer.class}))
public class PageInterception implements Interceptor {
  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    System.out.println("====");
    StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
    BoundSql boundSql = statementHandler.getBoundSql();
    Object parameterObject = boundSql.getParameterObject();
    Page page = null;
    if(parameterObject instanceof Page){
      page = (Page)parameterObject;
    }else if (parameterObject instanceof Map){
      page = (Page) ((Map) parameterObject).values().stream().filter(v->v instanceof Page).findFirst().orElse(null);
    }
    //select * from users offset 0 limit 50;
    //1. 求总行数
    if(page!=null){
      int count = selectCount(invocation);
      //2.修改sql
      String newSql = String.format(" %s limit %s , %s ",boundSql.getSql(),page.getPageSize(),page.getOffSet());
      SystemMetaObject.forObject(boundSql).setValue("sql", newSql);
    }

    return invocation.proceed();
  }
  private int selectCount(Invocation invocation) throws SQLException {
    int count = 0;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
    try {
      StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
      String sql = statementHandler.getBoundSql().getSql();
      String tmp = "select count(0) " + sql.substring(sql.indexOf("from"),sql.length());
      Connection connection = (Connection)invocation.getArgs()[0];
      preparedStatement = connection.prepareStatement(tmp);
      statementHandler.getParameterHandler().setParameters(preparedStatement);
      resultSet = preparedStatement.executeQuery();
      if(resultSet.next()){
        count = resultSet.getInt(1);
      }
    }finally {
      if(resultSet != null && !resultSet.isClosed())resultSet.close();
      if(preparedStatement != null && !preparedStatement.isClosed())preparedStatement.close();
    }


    return count;
  }

  @Override
  public Object plugin(Object target) {
    System.out.println("*****"+ target.getClass().getName());
    return Plugin.wrap(target,this);
  }

  @Override
  public void setProperties(Properties properties) {
    System.out.println("--------"+properties.getProperty("aa"));
  }
}

package com.wfg.interceptor;

/**
 * @author wufagang
 * @description
 * @date 2021年10月24日 15:51
 */
public class Page {
  private Integer index;
  private Integer total;
  private Integer pageSize;

  public Integer getIndex() {
    return index;
  }

  public void setIndex(Integer index) {
    this.index = index;
  }

  public Integer getTotal() {
    return total;
  }

  public void setTotal(Integer total) {
    this.total = total;
  }

  public Integer getPageSize() {
    return pageSize;
  }

  public void setPageSize(Integer pageSize) {
    this.pageSize = pageSize;
  }

  public Integer getOffSet(){
    return pageSize*(index-1);
  }
}

总结

mybatis 插件机制_第4张图片
关键代码:

/*
 *    Copyright 2009-2021 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.plugin;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.ibatis.reflection.ExceptionUtil;
import org.apache.ibatis.util.MapUtil;

/**
 * @author Clinton Begin
 */
public class Plugin implements InvocationHandler {

  private final Object target;
  private final Interceptor interceptor;
  private final Map, Set> signatureMap;

  private Plugin(Object target, Interceptor interceptor, Map, Set> signatureMap) {
    this.target = target;
    this.interceptor = interceptor;
    this.signatureMap = signatureMap;
  }

  public static Object wrap(Object target, Interceptor interceptor) {
    //获取配置的签名
    Map, Set> 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;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      Set methods = signatureMap.get(method.getDeclaringClass());
      if (methods != null && methods.contains(method)) {
        //匹配成功后 调用我们自定义的intercept中的intercept方法
        return interceptor.intercept(new Invocation(target, method, args));
      }
      return method.invoke(target, args);
    } catch (Exception e) {
      throw ExceptionUtil.unwrapThrowable(e);
    }
  }

  private static Map, Set> getSignatureMap(Interceptor interceptor) {
    Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
    // issue #251
    if (interceptsAnnotation == null) {
      throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
    }
    Signature[] sigs = interceptsAnnotation.value();
    Map, Set> signatureMap = new HashMap<>();
    for (Signature sig : sigs) {
      Set methods = MapUtil.computeIfAbsent(signatureMap, sig.type(), k -> new HashSet<>());
      try {
        Method method = sig.type().getMethod(sig.method(), sig.args());
        methods.add(method);
      } catch (NoSuchMethodException e) {
        throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);
      }
    }
    return signatureMap;
  }

  private static Class[] getAllInterfaces(Class type, Map, Set> signatureMap) {
    Set> interfaces = new HashSet<>();
    while (type != null) {
      for (Class c : type.getInterfaces()) {
        if (signatureMap.containsKey(c)) {
          interfaces.add(c);
        }
      }
      type = type.getSuperclass();
    }
    return interfaces.toArray(new Class[0]);
  }

}

sql统计功能

基于Executor 进行拦截,需要拦截缓存命中数据

这两个功能分布可以看看PagePlugi 和duri中功能是如何实现的进行学习对比

你可能感兴趣的:(#,mybatis,1024程序员节,interceptor,插件,分页,sql)