• Spring之AOP动态代理


    1、jdk代理

    • 代理类没有源码,在运行期间直接生成字节码,通过传入的类加载器加载
    • 为了实现功能的增强,添加前置通知、后置通知,环绕通知等
    • 代理类和目标对象是兄弟关系,都是实现了某个接口
    • 目标类可以被final修饰,不可被继承,不影响兄弟对象(代理类)创建
    public class JdkProxyDemo {
        public static void main(String[] param) throws IOException {
            // 目标对象
            Target target = new Target();
            // 用来加载在运行期间动态生成的字节码
            ClassLoader loader = JdkProxyDemo.class.getClassLoader();
            // p:代理类本身
            // method:代理类执行的方法
            // args:执行方法的参数
            Foo proxy = (Foo) Proxy.newProxyInstance(loader, new Class[]{Foo.class}, (p, method, args) -> {
                System.out.println("before...");
                // 目标.方法(参数)
                // 方法.invoke(目标, 参数);
                Object result = method.invoke(target, args);
                System.out.println("after....");
                return result; // 让代理也返回目标方法执行的结果
            });
            System.out.println("代理类类型:"+proxy.getClass());
            System.out.println("---------------通过代理类调用目标方法-----------");
            proxy.foo();
        }
    }
    
    interface Foo {
        void foo();
    }
    
    class Target implements Foo {
        public void foo() {
            System.out.println("target foo");
        }
    }
    
    • 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

    输出结果:

    代理类类型:class com.xc.a11.$Proxy0
    ---------------通过代理类调用目标方法-----------
    before...
    target foo
    after....
    
    Process finished with exit code 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2、cglib代理

    • 代理是子类型, 目标是父类型,所以目标类和方法都不能为final
    • methodProxy 可以避免使用反射调用,spring默认使用
    • 与jdk代理一样也是没有class文件,运行期间直接生成字节码文件
    public class CglibProxyDemo {
        // 代理是子类型, 目标是父类型
        public static void main(String[] param) {
    //        Target target = new Target();
            Target proxy = (Target) Enhancer.create(Target.class, (MethodInterceptor) 
            (p, method, args, methodProxy) -> {
      			System.out.println("before...");
    //            Object result = method.invoke(target, args); // 用方法反射调用目标
                // methodProxy 它可以避免反射调用
    //            Object result = methodProxy.invoke(target, args); // 内部没有用反射, 需要目标 (spring)
                Object result = methodProxy.invokeSuper(p, args); // 内部没有用反射, 需要代理
                System.out.println("after...");
                return result;
            });
            proxy.foo();
        }
    }
    
    class Target {
        public void foo() {
            System.out.println("target foo");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    输出结果:

    before...
    target foo
    after...
    
    Process finished with exit code 0
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3、手写jdk代理

    • 接口和目标对象
    interface Foo {
        void foo();
        int bar();
    }
    
    class Target implements Foo {
        public void foo() {
            System.out.println("target foo");
        }
        @Override
        public int bar() {
            System.out.println("target bar");
            return 100;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 代理类实现功能增强的方法的接口
    • 参数分别为:代理类本身,代理类执行的方法,方法参数
    interface InvocationHandler {
        Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
    }
    
    • 1
    • 2
    • 3
    • 核心代理类
    • 构造方法,传入功能增强接口的实现类
    public class $Proxy0 implements Foo {
    
    	//构造函数,创建代理类需要服务执行接口(增强方法的实现类)
        private final InvocationHandler invocationHandler;
        public $Proxy0(InvocationHandler h) {
            this.invocationHandler = h;
        }
    
    	//下面的方法会多次调用,用到method,这里静态代码块初始化一次
        private static final Method foo;
        private static final Method bar;
        static {
            try {
                foo = Foo.class.getMethod("foo");
                bar = Foo.class.getMethod("bar");
            } catch (NoSuchMethodException e) {
                throw new NoSuchMethodError(e.getMessage());
            }
        }
    
        @Override
        public void foo() {
            try {
            	//无返回:调用代理类实现功能增强的方法
                invocationHandler.invoke(this, foo, new Object[0]);
            } catch (RuntimeException | Error e) {
                throw e;
            } catch (Throwable e) {
                throw new UndeclaredThrowableException(e);
            }
        }
    
        @Override
        public int bar() {
            try {
            	//有返回:调用代理类实现功能增强的方法
                Object result = invocationHandler.invoke(this, bar, new Object[0]);
                return (int) result;
            } catch (RuntimeException | Error e) {
                throw e;
            } catch (Throwable e) {
                throw new UndeclaredThrowableException(e);
            }
        }
    }
    
    • 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
    • 创建代理类传入InvocationHandler的匿名内部类
    • 通过目标对象Target反射调用对应方法,前后可以添加功能增强
    public static void main(String[] param) {
        //创建对应接口的代理
        Foo proxy = new $Proxy0(new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
                // 1. 功能增强
                System.out.println("before...");
                // 2. 调用目标
                Object invoke = method.invoke(new Target(), args);
                // 3. 功能增强
                System.out.println("after...");
                return invoke;
            }
        });
        //调用接口代理的方法
        proxy.foo();
        proxy.bar();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    输出结果:

    before...
    target foo
    after...
    before...
    target bar
    after...
    
    Process finished with exit code 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    JDK动态代理实现与上方不同的是:没有class文件,在程序运行期间的内存中生成以上的字节码文件,所以叫动态代理

    4、手写cglib代理

    4.1、反射之目标调用

    • 目标类及多个方法
    public class Target {
        public void save() {
            System.out.println("save()");
        }
    
        public void save(int i) {
            System.out.println("save(int)");
        }
    
        public void save(long j) {
            System.out.println("save(long)");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 代理类,继承目标类,目标类的子类
    • 创建代理类需要MethodInterceptor接口实现类(环绕增强方法及中间的调用目标方法)
    • 代理类调用方法即是调用MethodInterceptor实现类的内容
    public class Proxy extends Target {
    
        private MethodInterceptor methodInterceptor;
    
        public Proxy(MethodInterceptor methodInterceptor) {
            this.methodInterceptor = methodInterceptor;
        }
    
        private final static Method save0;
        private final static Method save1;
        private final static Method save2;
        private final static MethodProxy save0Proxy;
        private final static MethodProxy save1Proxy;
        private final static MethodProxy save2Proxy;
        static {
            try {
                save0 = Target.class.getMethod("save");
                save1 = Target.class.getMethod("save", int.class);
                save2 = Target.class.getMethod("save", long.class);
                save0Proxy = MethodProxy.create(Target.class, Proxy.class, "()V", "save", "saveSuper");
                save1Proxy = MethodProxy.create(Target.class, Proxy.class, "(I)V", "save", "saveSuper");
                save2Proxy = MethodProxy.create(Target.class, Proxy.class, "(J)V", "save", "saveSuper");
            } catch (NoSuchMethodException e) {
                throw new NoSuchMethodError(e.getMessage());
            }
        }
        
        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 带原始功能的方法
        public void saveSuper() {
            super.save();
        }
        public void saveSuper(int i) {
            super.save(i);
        }
        public void saveSuper(long j) {
            super.save(j);
        }
        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 带增强功能的方法
        @Override
        public void save() {
            try {
                methodInterceptor.intercept(this, save0, new Object[0], save0Proxy);
            } catch (Throwable e) {
                throw new UndeclaredThrowableException(e);
            }
        }
    
        @Override
        public void save(int i) {
            try {
                methodInterceptor.intercept(this, save1, new Object[]{i}, save1Proxy);
            } catch (Throwable e) {
                throw new UndeclaredThrowableException(e);
            }
        }
    
        @Override
        public void save(long j) {
            try {
                methodInterceptor.intercept(this, save2, new Object[]{j}, save2Proxy);
            } catch (Throwable e) {
                throw new UndeclaredThrowableException(e);
            }
        }
    }
    
    // 环绕增强方法及中间的调用目标方法的接口
    public interface MethodInterceptor extends Callback {
        Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
    }
    
    • 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
    • method.invoke(target, args): 通过目标类获取到method,再利用method,target,args反射调用方法
    • methodProxy.invoke(target, args): 通过目标类直接调用方法,无反射
    • methodProxy.invokeSuper(p, args): 通过代理类调用方法,无反射
    • MethodProxy.create:创建methodProxy,内部调用saveSuper(带原始功能的方法)
    public class A13 {
        public static void main(String[] args) {
            //目标类
            Target target = new Target();
            //代理类
            Proxy proxy = new Proxy(new MethodInterceptor() {
                @Override
                public Object intercept(Object p, Method method, Object[] args,
                                        MethodProxy methodProxy) throws Throwable {
                    System.out.println("before...");
                    return method.invoke(target, args); // 反射调用
                    // FastClass
    //                return methodProxy.invoke(target, args); // 内部无反射, 结合目标用
    //                return methodProxy.invokeSuper(p, args); // 内部无反射, 结合代理用
                }
            });
            proxy.save();
            proxy.save(1);
            proxy.save(2L);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    输出结果:

    before...
    save()
    before...
    save(int)
    before...
    save(long)
    
    Process finished with exit code 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4.2、无反射之目标调用

    methodProxy.invoke(target, args):methodProxy对象的创建及invoke的执行原理

    • Signature:签名(描述方法名字-save及方法入参-()和方法返回值-V
    • 每个方法指定一个唯一的编号通过getIndex方法与签名一一对应
    • 在invoke中通过编号使用目标类调用不同的方法
    public class TargetFastClass {
        private final static Signature s0 = new Signature("save", "()V");
        private final static Signature s1 = new Signature("save", "(I)V");
        private final static Signature s2 = new Signature("save", "(J)V");
    
        // 获取目标方法的编号
        /*
            Target
                save()              0
                save(int)           1
                save(long)          2
            signature 包括方法名字、参数返回值
         */
        public int getIndex(Signature signature) {
            if (s0.equals(signature)) {
                return 0;
            } else if (s1.equals(signature)) {
                return 1;
            } else if (s2.equals(signature)) {
                return 2;
            }
            return -1;
        }
    
        // 根据方法编号, 正常调用目标对象方法
        public Object invoke(int index, Object target, Object[] args) {
            if (index == 0) {
                ((Target) target).save();
                return null;
            } else if (index == 1) {
                ((Target) target).save((int) args[0]);
                return null;
            } else if (index == 2) {
                ((Target) target).save((long) args[0]);
                return null;
            } else {
                throw new RuntimeException("无此方法");
            }
        }
    
        public static void main(String[] args) {
            TargetFastClass fastClass = new TargetFastClass();
            int index = fastClass.getIndex(new Signature("save", "(I)V"));
            System.out.println(index);
            fastClass.invoke(index, new Target(), new Object[]{100});
        }
    }
    
    • 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

    输出结果:这里的方法是目标类直接调用的save(int i)方法

    1
    save(int)
    
    Process finished with exit code 0
    
    • 1
    • 2
    • 3
    • 4

    4.3、无反射之代理调用

    methodProxy.invokeSuper(p, args):methodProxy对象的创建及invokeSuper的执行原理

    • 签名和方法标号与无反射目标调用一样
    • invoke则是通过代理类调用saveSuper方法的super.save(),实际还是目标类的方法实现
    public class ProxyFastClass {
        static Signature s0 = new Signature("saveSuper", "()V");
        static Signature s1 = new Signature("saveSuper", "(I)V");
        static Signature s2 = new Signature("saveSuper", "(J)V");
    
        // 获取代理方法的编号
        /*
            Proxy
                saveSuper()              0
                saveSuper(int)           1
                saveSuper(long)          2
            signature 包括方法名字、参数返回值
         */
        public int getIndex(Signature signature) {
            if (s0.equals(signature)) {
                return 0;
            } else if (s1.equals(signature)) {
                return 1;
            } else if (s2.equals(signature)) {
                return 2;
            }
            return -1;
        }
    
        // 根据方法编号, 正常调用目标对象方法
        public Object invoke(int index, Object proxy, Object[] args) {
            if (index == 0) {
                ((Proxy) proxy).saveSuper();
                return null;
            } else if (index == 1) {
                ((Proxy) proxy).saveSuper((int) args[0]);
                return null;
            } else if (index == 2) {
                ((Proxy) proxy).saveSuper((long) args[0]);
                return null;
            } else {
                throw new RuntimeException("无此方法");
            }
        }
    
        public static void main(String[] args) {
            ProxyFastClass fastClass = new ProxyFastClass();
            int index = fastClass.getIndex(new Signature("saveSuper", "()V"));
            System.out.println(index);
    
            fastClass.invoke(index, new Proxy(null), new Object[0]);
        }
    }
    
    • 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

    输出结果: 这里只需要代理类里面的saveSuper方法,MethodInterceptor这里没有用到

    0
    save()
    
    Process finished with exit code 0
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    基于SSM的网络教学(作业)管理系统
    什么是数据描述统计分析?(Descriptive Analysis)
    Delay Penalty for RNN-T and CTC
    社工工具演示
    [附源码]java毕业设计海雨市高校实验设备报修系统
    Linux 文件搜索命令:find
    【LeetCode刷题】2两数相加
    【Java+SpringBoot】小区物业管理系统(源码+代码讲解+答辩教学+毕设选题)
    内存函数的介绍和模拟实现
    Flutter 知识集锦 | 监听与通知 ChangeNotifier
  • 原文地址:https://blog.csdn.net/qq_35512802/article/details/126236585