• Mybatis 拦截器 说明和使用 (一)


    一.拦截器简介

    本节不介绍使用,先说原理

    Mybatis 定义了四个处理器,用于做 SQL 执行的默认处理;如果我们不添加拦截器,则 Mybatis 会按默认操作进行处理。
    如果添加了拦截器,则其会先执行拦截器内的增强处理,基于JDK动态代理实现,再进行默认操作
    PageHelper 分页插件就是基于拦截器实现的
    其次,自定义拦截器要注意顺序问题,先注册的后生效,后注册的先生效,为什么这样下面会提到
    
    • 1
    • 2
    • 3
    • 4

    二.拦截器实现说明

    参考 Mybatis 实现写了一个演示 Demo,Mybatis 的应用下节介绍
    
    • 1

    1.拦截器链

    /**
     * 拦截器链
     */
    static class InterceptorChain{
        private final List<Interceptor> interceptors = new ArrayList<>();
    
        /**
         * 获取SqlSession时生成拦截器链代理类
         * @param target
         * @return
         */
        public Object pluginAll(Object target) {
            //第一次添加的拦截器对象,生成代理对象,原对象指向新生成的代理对象
            //第二次新的代理对象作为原对象,生成代理对象...
            //循环,直到所有注册的拦截器都遍历一遍
            for (Interceptor interceptor : interceptors) {
                target = interceptor.plugin(target);
            }
            return target;
        }
    
        /**
         * 依次添加拦截器实现
         * @param interceptor
         */
        public void addInterceptor(Interceptor interceptor) {
            interceptors.add(interceptor);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    2.拦截器接口

    用于实现自定义拦截器的接口,可以在实现类内添加自定义的操作

    /**
     * 拦截器接口
     * 拦截方法参数类,封装了 被代理类、方法对象类、参数 属性
     */
    public interface Interceptor {
    
        /**
         * 拦截方法
         * @param invocation
         * @return
         * @throws Throwable
         */
        Object intercept(Invocation invocation) throws Throwable;
    
        /**
         * 插件包裹:将目标类封装逐层包裹
         * @param target
         * @return
         */
        default Object plugin(Object target) {
            return Plugin.wrap(target, this);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    3.执行器类

    封装了被代理对象、方法对象、参数集合三个属性,还有一个 proceed 方法,proceed 内基于反射实现了被代理类方法的调用;此类即为拦截器方法的参数

    /**
     * 执行器
     */
    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 getTarget() {
            return target;
        }
    
        public Method getMethod() {
            return method;
        }
    
        public Object[] getArgs() {
            return args;
        }
    
        /**
         * Proceed 实际就是反射中方法对象的Invoke
         * @return
         * @throws InvocationTargetException
         * @throws IllegalAccessException
         */
        public Object proceed() throws InvocationTargetException, IllegalAccessException {
            return method.invoke(target, args);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    4.拦截器注解定义

    1.拦截器注解

    用于标识,哪个类是 Mybatis 拦截类,同时如果在SpringBoot框架下可结合 @Component 注解直接将自定义拦截器注册到上面的链内,但是要注意顺序问题,多个自定义拦截器最好手动注册,当前类取了下面的签名类集合作为值

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface Intercepts {
        /**
         * 签名注解
         * @return
         */
        Signature[] value();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.方法签名注解

    签名注解,表明拦截的是哪个处理器的哪个方法,即三个属性:方法名、类、方法参数类型;此处取值原理仍与反射机制相关,不清楚反射的可以参考下面Demo理解一下

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    public @interface Signature{
    
        /**
         * 方法名,拦截类,方法参数类型
         * @return
         */
        String method();
        Class<?> type();
        Class<?>[] args();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3.反射Demo

    package entity;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    /**
     * @author 
     * @date 2022-10-16 21:37
     * @since 1.8
     */
    public class ReflexTest {
    
    
        public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    
            Reflex reflex = new Reflex();
    
            Method method = Reflex.class.getMethod("print", Integer.class);
    
            method.invoke(reflex,0);
    
            method = Reflex.class.getMethod("print", Integer.class,String.class);
    
            method.invoke(reflex,1,"model");
    
        }
    
        static class Reflex{
    
            /**
             * 打印测试
             * @param type
             */
            public void print(Integer type){
                System.out.println("单一参数:" + type);
            }
    
            /**
             * 打印测试
             * @param type
             * @param model
             */
            public void print(Integer type,String model){
                System.out.println("多个参数:" + type + ":" + model);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    在这里插入图片描述

    5.默认处理器类

    定义了两个默认处理器接口,用于演示,Mybatis 实际存在四个处理器类,用于实现参数处理、SQL处理、结果处理等操作;自定义拦截器是实现拦截器接口,不是实现处理器接口,处理器接口用于注册方法签名时要处理哪个处理器类的哪个方法

    1.处理器一

    接口

    /**
     * 处理器接口
     */
    public interface FirstHandler{
        String query(String type,Integer param);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    实现

    //默认实现
    static class FirstHandlerImpl implements FirstHandler{
    
        @Override
        public String query(String type,Integer param) {
           switch (param){
               case 0:
                   return "零";
               case 1:
                   return "一";
               case 2:
                   return "二";
               default:
                   return "default";
           }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.处理器二

    接口

    /**
     * 处理器接口
     */
    public interface SecondHandler{
        String select(Integer param);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    实现

    //默认实现
    static class SecondHandlerImpl implements SecondHandler{
    
        @Override
        public String select(Integer param) {
            switch (param){
                case 0:
                    return "SecondHandler:零";
                case 1:
                    return "SecondHandler:一";
                case 2:
                    return "SecondHandler:二";
                default:
                    return "SecondHandler:default";
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    6.插件类(核心操作)

    此类定义了一个 wrap 方法,用于包裹被代理类,会从默认处理器开始按注册顺序逐层包裹,最后全部包裹完成,返回代理对象,通过代理对象调用时会从外向内逐层调用,Plugin 完全取自Mybatis,没有修改,同学可以根据注释自己理解一下,这也是上面提到的先注册后执行,后注册先执行的原理,同时可能因此产生覆盖效果(后处理的覆盖先处理的)

    /**
     * 插件类生成动态代理,实现InvocationHandler
     */
    static 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;
        }
    
        /**
         * 包裹拦截器
         * @param target
         * @param interceptor
         * @return
         */
        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) {
                //基于JDK动态代理方式(接口反射)生成代理类
                return Proxy.newProxyInstance(
                        type.getClassLoader(),
                        //接口类
                        interfaces,
                        //封装了每层循环的原始被代理对象,拦截器类 和 注册的实现方法
                        new Plugin(target, interceptor, signatureMap));
            }
            //否则返回被代理对象(原对象)
            return target;
        }
    
        /**
         * 调用(增强实现)
         *
         * @return
         * @throws Throwable
         */
        @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)) {
                    //代理调用
                    return interceptor.intercept(new Invocation(target, method, args));
                }
                //未注册拦截器时直接调用原对象
                return method.invoke(target, args);
            } catch (Exception e) {
                //TODO 抛出异常
                System.out.println(e);
                return null;
            }
        }
    
        /**
         * 根据签名注解取出要处理的类和方法
         * @param interceptor
         * @return
         */
        private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
            //获取自定义拦截器上的拦截器类注解
            Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
            //TODO 非空校验,如果没有指定的注解,则无需向下解析了
            //获取值,签名集合
            Signature[] sigs = interceptsAnnotation.value();
            //定义一个 HashMap 缓存签名类和方法集合
            Map<Class<?>, Set<Method>> signatureMap = new HashMap<>();
            for (Signature sig : sigs) {
                //按操作类取方法集合,存在则取出,否则新建
                Set<Method> methods = computeIfAbsent(signatureMap, sig.type(), k -> new HashSet<>());
                try {
                    //根据方法名和参数类型,取签名类的方法对象,并添加到集合
                    Method method = sig.type().getMethod(sig.method(), sig.args());
                    methods.add(method);
                } catch (NoSuchMethodException e) {
                    //TODO 抛出异常
                }
            }
            //添加完成后返回签名缓存
            return signatureMap;
        }
    
        /**
         * 递归取出所有实现的接口类集合
         * @param type
         * @param signatureMap
         * @return
         */
        private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) {
            //定义接口类集合
            Set<Class<?>> interfaces = new HashSet<>();
            //类不为NULL
            while (type != null) {
                //遍历目标类所实现的接口类
                for (Class<?> c : type.getInterfaces()) {
                    //如果是被注册的方法类,就添加到集合
                    if (signatureMap.containsKey(c)) {
                        interfaces.add(c);
                    }
                }
                //取父类(单继承多实现,如果没有显示继承某个父类,则取出结果为Object类,再取则为NULL,循环结束)
                type = type.getSuperclass();
            }
            //返回注册的接口类的数组
            return interfaces.toArray(new Class<?>[0]);
        }
    
        /**
         * 对 MAP 官方方法做了一层封装,不存在则创建一个值对象并返回
         * @param map
         * @param key
         * @param mappingFunction
         * @return
         * @param 
         * @param 
         */
        public static <K, V> V computeIfAbsent(Map<K, V> map, K key, Function<K, V> mappingFunction) {
            V value = map.get(key);
            if (value != null) {
                return value;
            }
            return map.computeIfAbsent(key, mappingFunction);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134

    7.自定义拦截器(测试)

    上面的代码已经实现了拦截器框架,下面定义两个测试类验证一下

    1.混合拦截

    @Intercepts({
                @Signature(method = "query", type = FirstHandler.class,args = {String.class,Integer.class}),
                @Signature(method = "query", type = SecondHandler.class,args = {Integer.class}),
        })
    static class MyInterceptor implements Interceptor{
    
         /**
          * 拦截器实现
          * @param invocation
          * @return
          * @throws Throwable
          */
         @Override
         public Object intercept(Invocation invocation) throws Throwable {
    
             //TODO 增强处理
             invocation.getArgs()[1] = 2;
    
             //反射对象Invocation,Proceed实际封装了方法调用:method.invoke(target, args) 此处即被代理类调用
             return invocation.proceed();
         }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.仅拦截第一类处理器

    /**
     * 第二处理 拦截 1
     */
    @Intercepts({
            @Signature(method = "select", type = SecondHandler.class,args = {Integer.class}),
    })
    static class SecondInterceptorOne implements Interceptor{
    
        /**
         * 拦截器实现
         * @param invocation
         * @return
         * @throws Throwable
         */
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
    
            //TODO 增强处理
            invocation.getArgs()[0] = 1;
    
            //反射对象Invocation,Proceed实际封装了方法调用:method.invoke(target, args) 此处即被代理类调用
            return invocation.proceed();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3.仅拦截第二类处理

    /**
     * 第二处理 拦截 2
     */
    @Intercepts({
            @Signature(method = "select", type = SecondHandler.class,args = {Integer.class}),
    })
    static class SecondInterceptorTwo implements Interceptor{
    
        /**
         * 拦截器实现
         * @param invocation
         * @return
         * @throws Throwable
         */
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
    
            //TODO 增强处理
            invocation.getArgs()[0] = 2;
    
            //反射对象Invocation,Proceed实际封装了方法调用:method.invoke(target, args) 此处即被代理类调用
            return invocation.proceed();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    三.测试

    将上面所有类和方法写到一个测试类,并通过主方法调用验证

    package entity;
    
    import java.lang.annotation.*;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.*;
    import java.util.function.Function;
    
    /**
     * @author 
     * @date 2022-10-12 17:43
     * @since 1.8
     */
    public class TEST {
    
        /**
         * 测试类
         * 拦截器链是先注册拦截器实现类,再逐层生成动态代理,
         * 最先注册的是最原始被代理对象,最后注册的是最新代理对象,
         * 所以使用时是最后注册的拦截器类先生效,先注册的后生效,同时可能因此后生效的会覆盖先生效的处理
         *
         * Mybatis 拦截器在使用时,他会自己最先 New 一个默认的被代理类作为参数传给 pluginAll 然后才开始包裹拦截器链的实现类
         * @param args
         */
        public static void main(String[] args) {
    
            InterceptorChain chain = new InterceptorChain();
    
            chain.addInterceptor(new MyInterceptor());
    
            chain.addInterceptor(new SecondInterceptorOne());
    
            chain.addInterceptor(new SecondInterceptorTwo());
    
            FirstHandler firsthandler = (FirstHandler) chain.pluginAll(new FirstHandlerImpl());
    
            String result = firsthandler.query("",0);
    
            System.out.println(result);
    
            SecondHandler secondHandler = (SecondHandler) chain.pluginAll(new SecondHandlerImpl());
    
            System.out.println(secondHandler.select(0));
    
        }
    
        @Intercepts({
                @Signature(method = "query", type = FirstHandler.class,args = {String.class,Integer.class}),
                @Signature(method = "query", type = SecondHandler.class,args = {Integer.class}),
        })
        static class MyInterceptor implements Interceptor{
    
            /**
             * 拦截器实现
             * @param invocation
             * @return
             * @throws Throwable
             */
            @Override
            public Object intercept(Invocation invocation) throws Throwable {
    
                //TODO 增强处理
                invocation.getArgs()[1] = 2;
    
                //反射对象Invocation,Proceed实际封装了方法调用:method.invoke(target, args) 此处即被代理类调用
                return invocation.proceed();
            }
        }
    
        /**
         * 第二处理 拦截 1
         */
        @Intercepts({
                @Signature(method = "select", type = SecondHandler.class,args = {Integer.class}),
        })
        static class SecondInterceptorOne implements Interceptor{
    
            /**
             * 拦截器实现
             * @param invocation
             * @return
             * @throws Throwable
             */
            @Override
            public Object intercept(Invocation invocation) throws Throwable {
    
                //TODO 增强处理
                invocation.getArgs()[0] = 1;
    
                //反射对象Invocation,Proceed实际封装了方法调用:method.invoke(target, args) 此处即被代理类调用
                return invocation.proceed();
            }
        }
    
        /**
         * 第二处理 拦截 2
         */
        @Intercepts({
                @Signature(method = "select", type = SecondHandler.class,args = {Integer.class}),
        })
        static class SecondInterceptorTwo implements Interceptor{
    
            /**
             * 拦截器实现
             * @param invocation
             * @return
             * @throws Throwable
             */
            @Override
            public Object intercept(Invocation invocation) throws Throwable {
    
                //TODO 增强处理
                invocation.getArgs()[0] = 2;
    
                //反射对象Invocation,Proceed实际封装了方法调用:method.invoke(target, args) 此处即被代理类调用
                return invocation.proceed();
            }
        }
    
    
        /**
         * 拦截器链
         */
        static class InterceptorChain{
            private final List<Interceptor> interceptors = new ArrayList<>();
    
            /**
             * 获取SqlSession时生成拦截器链代理类
             * @param target
             * @return
             */
            public Object pluginAll(Object target) {
                //第一次添加的拦截器对象,生成代理对象,原对象指向新生成的代理对象
                //第二次新的代理对象作为原对象,生成代理对象...
                //循环,直到所有注册的拦截器都遍历一遍
                for (Interceptor interceptor : interceptors) {
                    target = interceptor.plugin(target);
                }
                return target;
            }
    
            /**
             * 依次添加拦截器实现
             * @param interceptor
             */
            public void addInterceptor(Interceptor interceptor) {
                interceptors.add(interceptor);
            }
    
        }
    
        /**
         * 拦截器接口
         * 拦截方法参数类,封装了 被代理类、方法对象类、参数 属性
         */
        public interface Interceptor {
    
            /**
             * 拦截方法
             * @param invocation
             * @return
             * @throws Throwable
             */
            Object intercept(Invocation invocation) throws Throwable;
    
            /**
             * 插件包裹:将目标类封装逐层包裹
             * @param target
             * @return
             */
            default Object plugin(Object target) {
                return Plugin.wrap(target, this);
            }
        }
    
        /**
         * 处理器接口
         */
        public interface FirstHandler{
            String query(String type,Integer param);
        }
    
        //默认实现
        static class FirstHandlerImpl implements FirstHandler{
    
            @Override
            public String query(String type,Integer param) {
               switch (param){
                   case 0:
                       return "零";
                   case 1:
                       return "一";
                   case 2:
                       return "二";
                   default:
                       return "default";
               }
            }
        }
    
        /**
         * 处理器接口
         */
        public interface SecondHandler{
            String select(Integer param);
        }
    
        //默认实现
        static class SecondHandlerImpl implements SecondHandler{
    
            @Override
            public String select(Integer param) {
                switch (param){
                    case 0:
                        return "SecondHandler:零";
                    case 1:
                        return "SecondHandler:一";
                    case 2:
                        return "SecondHandler:二";
                    default:
                        return "SecondHandler:default";
                }
            }
        }
    
        @Documented
        @Retention(RetentionPolicy.RUNTIME)
        @Target(ElementType.TYPE)
        public @interface Intercepts {
            /**
             * 签名注解
             * @return
             */
            Signature[] value();
        }
    
        @Documented
        @Retention(RetentionPolicy.RUNTIME)
        @Target({})
        public @interface Signature{
    
            /**
             * 方法名,拦截类,方法参数类型
             * @return
             */
            String method();
            Class<?> type();
            Class<?>[] args();
        }
    
        /**
         * 执行器
         */
        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 getTarget() {
                return target;
            }
    
            public Method getMethod() {
                return method;
            }
    
            public Object[] getArgs() {
                return args;
            }
    
            /**
             * Proceed 实际就是反射中方法对象的Invoke
             * @return
             * @throws InvocationTargetException
             * @throws IllegalAccessException
             */
            public Object proceed() throws InvocationTargetException, IllegalAccessException {
                return method.invoke(target, args);
            }
    
        }
    
        /**
         * 插件类生成动态代理,实现InvocationHandler
         */
        static 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;
            }
    
            /**
             * 包裹拦截器
             * @param target
             * @param interceptor
             * @return
             */
            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) {
                    //基于JDK动态代理方式(接口反射)生成代理类
                    return Proxy.newProxyInstance(
                            type.getClassLoader(),
                            //接口类
                            interfaces,
                            //封装了每层循环的原始被代理对象,拦截器类 和 注册的实现方法
                            new Plugin(target, interceptor, signatureMap));
                }
                //否则返回被代理对象(原对象)
                return target;
            }
    
            /**
             * 调用(增强实现)
             *
             * @return
             * @throws Throwable
             */
            @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)) {
                        //代理调用
                        return interceptor.intercept(new Invocation(target, method, args));
                    }
                    //未注册拦截器时直接调用原对象
                    return method.invoke(target, args);
                } catch (Exception e) {
                    //TODO 抛出异常
                    System.out.println(e);
                    return null;
                }
            }
    
            /**
             * 根据签名注解取出要处理的类和方法
             * @param interceptor
             * @return
             */
            private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
                //获取自定义拦截器上的拦截器类注解
                Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
                //TODO 非空校验,如果没有指定的注解,则无需向下解析了
                //获取值,签名集合
                Signature[] sigs = interceptsAnnotation.value();
                //定义一个 HashMap 缓存签名类和方法集合
                Map<Class<?>, Set<Method>> signatureMap = new HashMap<>();
                for (Signature sig : sigs) {
                    //按操作类取方法集合,存在则取出,否则新建
                    Set<Method> methods = computeIfAbsent(signatureMap, sig.type(), k -> new HashSet<>());
                    try {
                        //根据方法名和参数类型,取签名类的方法对象,并添加到集合
                        Method method = sig.type().getMethod(sig.method(), sig.args());
                        methods.add(method);
                    } catch (NoSuchMethodException e) {
                        //TODO 抛出异常
                    }
                }
                //添加完成后返回签名缓存
                return signatureMap;
            }
    
            /**
             * 递归取出所有实现的接口类集合
             * @param type
             * @param signatureMap
             * @return
             */
            private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) {
                //定义接口类集合
                Set<Class<?>> interfaces = new HashSet<>();
                //类不为NULL
                while (type != null) {
                    //遍历目标类所实现的接口类
                    for (Class<?> c : type.getInterfaces()) {
                        //如果是被注册的方法类,就添加到集合
                        if (signatureMap.containsKey(c)) {
                            interfaces.add(c);
                        }
                    }
                    //取父类(单继承多实现,如果没有显示继承某个父类,则取出结果为Object类,再取则为NULL,循环结束)
                    type = type.getSuperclass();
                }
                //返回注册的接口类的数组
                return interfaces.toArray(new Class<?>[0]);
            }
    
            /**
             * 对 MAP 官方方法做了一层封装,不存在则创建一个值对象并返回
             * @param map
             * @param key
             * @param mappingFunction
             * @return
             * @param 
             * @param 
             */
            public static <K, V> V computeIfAbsent(Map<K, V> map, K key, Function<K, V> mappingFunction) {
                V value = map.get(key);
                if (value != null) {
                    return value;
                }
                return map.computeIfAbsent(key, mappingFunction);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427

    结果

    拦截操作
    MyInterceptorFirstHandler 的 query(String type,Integer param)将第 2 个参数改为 2
    MyInterceptorSecondHandler 的 query(Integer param)方法不存在,所以不生效
    SecondInterceptorOneSecondHandler 的 select(Integer param)将参数改为 1
    SecondInterceptorTwoSecondHandler 的 select(Integer param)将参数改为 2

    拦截到处理器的调用,并修改其参数

    在这里插入图片描述

    最里面包裹的是默认实现

    在这里插入图片描述
    整体输出效果(部分异常捕获未处理,Mybatis 实际会抛出),SecondHandler 原始为 0 ,先修改为 2 ,后又修改为 1 ,修改被覆盖,最终返回了 “一”

    在这里插入图片描述

  • 相关阅读:
    【CATIA】—3DE高科技案例研究V-ZUG | 达索系统百世慧®
    自己动手搭建一个简单的网站
    责任链模式
    05. Hibernate 使用注解做元数据
    前端总结35.JS封装事件库
    docker和anaconda使用基础
    大规模新型冠状病毒疫情最优应对策略研究
    排序算法之详解冒泡排序
    C++教程 - How to C++系列专栏第6篇
    java计算机毕业设计ssm特大城市地铁站卫生防疫系统5i80c(附源码、数据库)
  • 原文地址:https://blog.csdn.net/weixin_42176639/article/details/127328845