初识_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();
    }
}

说明:

  • 代理对象和目标对象是平级的关系,不能相互强转,即使目标对象被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();

    }
}

代理类 普通类区别

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C_x_330

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值