Mybatis 插件机制

插件机制示例代码

package interceptor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MybatisPluginDemo {
    
    // 模拟Executor接口(Mybatis核心执行器)
    interface Executor {
        Object query(String sql);
    }
    
    // 模拟实际执行器实现
    static class SimpleExecutor implements Executor {
        @Override
        public Object query(String sql) {
            System.out.println("【执行SQL】: " + sql);
            return "查询结果: " + sql;
        }
    }
    
    // 模拟Mybatis的拦截器接口
    interface Interceptor {
        Object intercept(Invocation invocation) throws Throwable;
        default Object plugin(Object target) {
            return Plugin.wrap(target, this);
        }
    }
    
    // 模拟Mybatis的Invocation类
    static class Invocation {
        private final Object target;
        private final Method method;
        private final Object[] args;
        
        public Invocation(Object target, Method method, Object[] args) {
            this.target = target;
            this.method = method;
            this.args = args;
        }
        
        public Object proceed() throws Throwable {
            return method.invoke(target, args);
        }
    }
    
    // 模拟Mybatis的Plugin工具类
    static class Plugin implements InvocationHandler {
        private final Object target;
        private final Interceptor interceptor;
        
        private Plugin(Object target, Interceptor interceptor) {
            this.target = target;
            this.interceptor = interceptor;
        }
        
        public static Object wrap(Object target, Interceptor interceptor) {
            // 获取目标对象的所有接口
            Class<?> type = target.getClass();
            Class<?>[] interfaces = type.getInterfaces();
            if (interfaces.length > 0) {
                // 创建动态代理
                return Proxy.newProxyInstance(
                    type.getClassLoader(),
                    interfaces,
                    new Plugin(target, interceptor)
                );
            }
            return target;
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 创建Invocation对象,交给拦截器处理
            return interceptor.intercept(new Invocation(target, method, args));
        }
    }
    
    // 自定义拦截器1:日志记录
    static class LogInterceptor implements Interceptor {
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            System.out.println("【日志拦截器】>>> 开始执行: " + invocation.method.getName() + 
                               ", 参数: " + Arrays.toString(invocation.args));
            Object result = invocation.proceed();
            System.out.println("【日志拦截器】<<< 执行完成,结果: " + result);
            return result;
        }
    }
    
    // 自定义拦截器2:性能监控
    static class PerformanceInterceptor implements Interceptor {
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            long start = System.currentTimeMillis();
            System.out.println("【性能拦截器】开始计时...");
            Object result = invocation.proceed();
            long duration = System.currentTimeMillis() - start;
            System.out.println("【性能拦截器】执行耗时: " + duration + "ms");
            return result;
        }
    }
    
    // 自定义拦截器3:SQL美化
    static class SqlFormatInterceptor implements Interceptor {
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            if ("query".equals(invocation.method.getName())) {
                String sql = (String) invocation.args[0];
                // 美化SQL(简化处理)
                String formattedSql = sql.replaceAll("\\s+", " ").trim();
                System.out.println("【SQL美化拦截器】原始SQL: " + sql);
                System.out.println("【SQL美化拦截器】美化后SQL: " + formattedSql);
                invocation.args[0] = formattedSql;
            }
            return invocation.proceed();
        }
    }
    
    // 模拟Mybatis的配置过程
    public static void main(String[] args) {
        // 1. 创建原始执行器
        Executor target = new SimpleExecutor();
        
        // 2. 创建拦截器
        List<Interceptor> interceptors = new ArrayList<>();
        interceptors.add(new LogInterceptor());
        interceptors.add(new PerformanceInterceptor());
        interceptors.add(new SqlFormatInterceptor());
        
        // 3. 应用所有拦截器(形成多层代理)
        System.out.println("开始创建多层代理...");
        for (Interceptor interceptor : interceptors) {
            target = (Executor) interceptor.plugin(target);
            System.out.println("添加拦截器: " + interceptor.getClass().getSimpleName());
        }
        
        System.out.println("\n代理对象类型: " + target.getClass().getName());
//        System.out.println("多层代理结构:");
//        printProxyChain(target, 0);
        
        // 4. 执行查询(触发代理链)
        System.out.println("\n执行查询操作:");
        Object result = target.query("   SELECT   *   FROM   users   WHERE   id   =   1  ");
        
        System.out.println("\n最终结果: " + result);
    }
    
    // 递归打印代理链结构
//    private static void printProxyChain(Object obj, int level) {
//        if (Proxy.isProxyClass(obj.getClass())) {
//            InvocationHandler handler = Proxy.getInvocationHandler(obj);
//            if (handler instanceof Plugin) {
//                Plugin plugin = (Plugin) handler;
//                System.out.println(repeat("  ", level) + "└─ 代理层 " + (level+1) + ": " +
//                                  plugin.interceptor.getClass().getSimpleName());
//
//                // 递归打印内层对象
//                printProxyChain(plugin.target, level + 1);
//            }
//        } else {
//            System.out.println(repeat("  ", level) + "└─ 目标对象: " + obj.getClass().getSimpleName());
//        }
//    }
    
//    private static String repeat(String str, int times) {
//        return new String(new char[times]).replace("\0", str);
//    }
}
  1. JDK动态代理创建的代理对象为Proxy类型
  2. 每个Proxy类型的代理对象都会关联一个InvocationHandler实现
  3. 调用代理对象的任何方法都会被转发其关联的InvocationHandler方法中。
  4. 而插件的InvocationHandler实际上是调用的插件对象的interceptor方法。
  5. interceptor方法中调用proceed方法进而又调用到了 method.invoke(target,args)
    method.invoke(target,args) 这一行的关键在于target对象的性质
    如果target对象为一个Proxy代理对象,则 method.invoke(target,args)执行时,依然会转发到target这个对象关联的InvocationHandler的invoke方法中,而如果target是一个普通对象,则会执行普通对象的方法。
    method.invoke(target,args) 在整个代理链执行的过程中,method和args是不变的,是原始调用中JVM封装好的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值