mybatis 插件机制

mybatis 4大插件

在这里插入图片描述

分页插件功能设计

在这里插入图片描述
在这里插入图片描述

代码

<plugins>
    <plugin interceptor="com.wfg.interceptor.PageInterception">
      <property name="aa" value="123"/>
    </plugin>
  </plugins>
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);
  }
}

总结

在这里插入图片描述
关键代码:

/*
 *    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<Class<?>, Set<Method>> signatureMap;

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

  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;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      Set<Method> 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<Class<?>, Set<Method>> 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<Class<?>, Set<Method>> signatureMap = new HashMap<>();
    for (Signature sig : sigs) {
      Set<Method> 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<Class<?>, Set<Method>> signatureMap) {
    Set<Class<?>> 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中功能是如何实现的进行学习对比

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值