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, 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]);
}
}
基于Executor 进行拦截,需要拦截缓存命中数据
这两个功能分布可以看看PagePlugi 和duri中功能是如何实现的进行学习对比