• 初识_JDK代理cglib代理_1


    JDK

    只能针对接口代理

    public class JdkProxy {
        interface Foo{
            void foo();
        }
        static class Target implements Foo{
    
            @Override
            public void foo() {
                System.out.println("foo ...");
            }
        }
    
        public static void main(String[] args) {
    
            //目标对象
            Target target = new Target();
    
            //用来加载运行期间代理生成的源代码
            ClassLoader classLoader = JdkProxy.class.getClassLoader();
            Foo fooProxy = (Foo)Proxy.newProxyInstance(classLoader, new Class[]{Foo.class}, (proxy, method, args1) -> {
                System.out.println("before...");
                // 目标.方法(参数)
                //方法.invoke(目标,参数)
                Object res = method.invoke(target, args1);
                System.out.println("after...");
    
                //代理返回目标方法执行的结果
                return res;
            });
    
            fooProxy.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

    说明:

    • 代理对象和目标对象是平级的关系,不能相互强转,即使目标对象被final修饰,也不影响代理对象的创建和执行

    cglib

    • 基于子父继承关系生成代理
    • 代理类是子类型,目标是父类型
    • 目标不能是final 类 ,并且里面的方法也不能被增强
    • 执行原始方法 通过cglib代理有三种方式
      • 通过反射 需要 目标对象
      • 内部不是用反射 需要 目标对象 Spring默认使用的就是这种
      • 内部不是用反射 不需要 目标对象 需要代理对象
      • 最后两种没用反射的调用的效率高于使用反射调用的方式
    • 下面通过代码演示,关键信息都通过注释方式展现出来了
    public class cglibProxy {
    
        static class Target{
            public  void foo(){
                System.out.println("target foo ...");
            }
        }
    
        public static void main(String[] args) {
            /*
            四个参数
            1.Object p      代表代理类自己
            2.Method method     代理类中执行的方法
            3.Object[] args   方法执行时的实际参数
            4.MethodProxy methodProxy 方法对象  避免反射来调用目标方法  内部没有用反射
             */
    
            Target target = new Target();
            //因为cglib代理和jdk代理不一样,jdk代理只能代理接口
            //所以我们定义的目标对象和代理对象之间时 平级(兄弟)关系,在这种情况下,代理对象不能转为目标对象
            //但是cglib代理和jdk代理不同,cglib代理  可以理解为  父子继承式  的代理,所以这个代理对象可以强转为父
    
            //final修饰类不能被继承,修饰方法不可被重写
            //此时这个代理相当于一个 子类,如果被代理的父类使用final修饰,那么就会报错~~~
            //IllegalArgumentException: Cannot subclass final class com.itheima.demo.cglibProxy$Target
            //如果我们在父类的方法上添加final来修饰方法,那么这个代理方法就会失效,仅仅会调用父类的方法,不能达到增强的效果
            Target tarProxy = (Target) Enhancer.create(Target.class, (MethodInterceptor) (p, method, args2, methodProxy) -> {
    
                System.out.println("before...");
                Object res = method.invoke(target,args2);
    //            Object res = methodProxy.invoke(target, args2);  //内部没用反射 依赖目标  Spring用的就是这种方式
    //            Object res = methodProxy.invokeSuper(p, args2);  //内部没用反射 依赖代理
                System.out.println("after...");
                return res;
            });
            tarProxy.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

    代理类 普通类区别

    普通类:先写Java源代码,—> Java字节码 —> 类加载 使用

    代理类:没有源码,在运行期间 直接生成代理类的源码,但是需要加载后才能运行

    那怎么加载呢? 通过 classLoader类加载器

  • 相关阅读:
    分账系统,聚合支付,第三方支付通道,应用在哪些场景?
    记录一次非常麻烦的调试
    网课自动暂停解决方法、挂课后台播放方法、解决继续教育自动暂停
    易基因:oxBS揭示口腔鳞癌的启动子区甲基化和羟甲基化变化及基因差异表达|项目文章
    自然语言处理(NLP)—— 神经网络自然语言处理(2)实际应用
    python 多线程编程(线程同步和守护线程)
    在win系统安装部署svn服务及客户端使用
    3D~RPG游戏的制作
    Express中间件(Middleware)
    数据结构与算法之图: Leetcode 417. 太平洋大西洋水流问题 (Typescript版)
  • 原文地址:https://blog.csdn.net/C_x_330/article/details/127555483