• Spring底层原理学习笔记--第十一讲--(aop之proxy增强-jdk及aop之proxy增强-cglib)


    AOP实现之proxy

    • 1.jdk动态代理实现及要点

    • 2.cglib代理实现及要点

      invoke与invokeSuper区别

    jdk动态代理实现及要点

    package com.lucifer.itheima.a12;
    
    import java.lang.reflect.Proxy;
    
    public class JdkProxyDemo {
    
        interface Foo{
            void foo();
        }
    
        //该类可以设置成final类型 
        //jdk中的代理跟目标是平级的兄弟关系,他们都实现了共同的接口
        static class Target implements Foo{
            public void foo(){
                System.out.println("target foo");
            }
        }
    
        //jdk只能对接口代理
        //cglib 没有限制,可以对接口代理,如果没有接口的话也可以
        public static void main(String[] param) {
    //        ClassLoader loader = JdkProxyDemo.class.getClassLoader();  // 用来加载在运行期间动态生成的字节码
    //        //ClassLoader的作用:
    //        // 代理类跟普通类有一个差别,普通类是先写java源代码,java源代码编译成java字节码,最后经过类加载然后可以使用
    //        // 而代理类没有源码,它是在运行期间,直接生成代理类的字节码,生成后的字节码也要被加载后才能运行,谁来做这个操作呢,由我们的Classloader来做这个操作
    //        //所以类加载器主要是用于加载代理类内部生成的字节码
    //
    //        Foo proxy = (Foo)Proxy.newProxyInstance(loader, new Class[] { Foo.class }, (p, method, args) -> {
    //            System.out.println("before...");
    //            return null;
    //        });
    //
    //        //参数二
    //        // 将来要生成的代理,要实现的是哪个接口
    //        // 参数三是干什么的,大家想代理类创建出来了,它也实现了我们的接口,它要实现接口中的抽象方法,必须规定这些方法的行为,那谁来把这些行为进行封装呢,就是第三个参数来做的
    //
    //        //总结:参数1: 用来加载在运行期间动态生成的字节码
    //        //参数2:将来要实现的接口
    //        //参数3:代理类调用任何代理方法时,要执行的一些行为
    //
    //
    //        //输出结果为
            before...
    //        proxy.foo();
    
    
            //目标对象
            Target target = new Target();
    
            ClassLoader loader = JdkProxyDemo.class.getClassLoader();   //用来加载在运行期间动态生成的字节码
            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;       //让代理也返回目标方法执行的结果
            });
    
    //        //输出结果为
    //        before...
    //        target foo
    //        after...
            proxy.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
    • 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

    cglib代理实现及要点

    package com.lucifer.itheima.a12;
    
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    
    public class CglibProxyDemo {
    
        // 该类不能设置成final类型  因为目标加了final 意味着将来不能有子类,但是代理就是想成为目标的子类型,所以会冲突
        static  class Target{
            // 这个方法如果是final类型的也不能增强,因为既然是子夫级的关系,那肯定是通过方法的重写来获得的增强,既然是方法重写,那对于final类型肯定不再适用,因为final的方法是不能被重写不能被继承的
            public final void foo() {
                //加了final之后的输出结果为
    //            target foo
                // 不会报错,但是不具备before、after的增强功能了
                System.out.println("target foo");
            }
        }
    
        //代理是子类型,目标是父类型
        //跟jdk的动态代理不一样,jdk中的代理跟目标是平级的兄弟关系,他们都实现了共同的接口
        public static void main(String[] args) {
            Target target = new Target();
            Target proxy = (Target)Enhancer.create(Target.class, (MethodInterceptor) (p, method, args1, methodProxy) -> {
                System.out.println("before...");
    //            Object result = method.invoke(target, args);    //用方法反射调用目标
    
                // methodProxy 它可以避免反射调用
    //            Object result = methodProxy.invoke(target,args);     //内部没有用反射,需要目标(spring)  但是看到的效果是一样的,都是输出//
                //            before...
                //        target foo
                //        after...  但是内部确实没有用反射
    
                Object result = methodProxy.invokeSuper(p,args);   //内部没有用反射,需要代理    但是看到的效果是一样的,都是输出//        before...
                //        target foo
                //        after...
                System.out.println("after...");
                return result;
            });
            //第一个参数:代理的父类是什么  第二个参数,决定将来代理类中方法执行的行为
            //o指的是代理类自己,method指的是当前代理类中执行的方法,args指的是方法执行时的参数,methodProxy也可以看作是一个方法对象
    
            //输出结果为
    //        before...
    //        target foo
    //        after...
            proxy.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
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
  • 相关阅读:
    如何为虚拟机添加磁盘,扩充原有分区的磁盘空间
    【uniapp】uview1.x 的 u-upload 上传点击删除隐藏 modal 提示框
    STM32液晶显示
    软件测试之如何提升产品的用户体验度
    【Acorn】JS解析器编译原理
    java毕业设计二手交易系统Mybatis+系统+数据库+调试部署
    Linux下路由表的转发流程
    JavaWeb笔记——VUE和ElementUI进阶
    36寸旅行小吉他怎么选?适合成人儿童初学入门的几款高性价比民谣小吉他品牌推荐!
    OpenCV官方教程中文版 —— 图像梯度
  • 原文地址:https://blog.csdn.net/weixin_42594143/article/details/134415495