• Spring系列七:JDK 动态代理和 CGLIB 代理


     JDK相信小伙伴们对它十分熟悉,那么小伙伴们知道JDK动态代理和CGLIB代理的区别吗?接下来由叶秋学长带领小伙伴对它们进行深入学习吧~~

    21.说说JDK 动态代理和 CGLIB 代理 ?

    Spring的AOP是通过动态代理来实现的,动态代理主要有两种方式JDK动态代理和Cglib动态代理,这两种动态代理的使用和原理有些不同。

    JDK 动态代理

    1. Interface:对于 JDK 动态代理,目标类需要实现一个Interface。

    2. InvocationHandler:InvocationHandler是一个接口,可以通过实现这个接口,定义横切逻辑,再通过反射机制(invoke)调用目标类的代码,在次过程,可能包装逻辑,对目标方法进行前置后置处理。

    3. Proxy:Proxy利用InvocationHandler动态创建一个符合目标类实现的接口的实例,生成目标类的代理对象。

    CgLib 动态代理

    1. 使用JDK创建代理有一大限制,它只能为接口创建代理实例,而CgLib 动态代理就没有这个限制。

    2. CgLib 动态代理是使用字节码处理框架 ASM,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

    3. CgLib 创建的动态代理对象性能比 JDK 创建的动态代理对象的性能高不少,但是 CGLib 在创建代理对象时所花费的时间却比 JDK 多得多,所以对于单例的对象,因为无需频繁创建对象,用 CGLib 合适,反之,使用 JDK 方式要更为合适一些。同时,由于 CGLib 由于是采用动态创建子类的方法,对于 final 方法,无法进行代理。

    我们来看一个常见的小场景,客服中转,解决用户问题:

    用户向客服提问题

    JDK动态代理实现:

    JDK动态代理类图

    • 接口

      1. public interface ISolver {
      2.     void solve();
      3. }
    • 目标类:需要实现对应接口

      1. public class Solver implements ISolver {
      2.     @Override
      3.     public void solve() {
      4.         System.out.println("疯狂掉头发解决问题……");
      5.     }
      6. }
    • 态代理工厂:ProxyFactory,直接用反射方式生成一个目标对象的代理对象,这里用了一个匿名内部类方式重写InvocationHandler方法,实现接口重写也差不多

      1. public class ProxyFactory {
      2.     // 维护一个目标对象
      3.     private Object target;
      4.     public ProxyFactory(Object target) {
      5.         this.target = target;
      6.     }
      7.     // 为目标对象生成代理对象
      8.     public Object getProxyInstance() {
      9.         return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
      10.                 new InvocationHandler() {
      11.                     @Override
      12.                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      13.                         System.out.println("请问有什么可以帮到您?");
      14.                         // 调用目标对象方法
      15.                         Object returnValue = method.invoke(target, args);
      16.                         System.out.println("问题已经解决啦!");
      17.                         return null;
      18.                     }
      19.                 });
      20.     }
      21. }
    • 客户端:Client,生成一个代理对象实例,通过代理对象调用目标对象方法

      1. public class Client {
      2.     public static void main(String[] args) {
      3.         //目标对象:程序员
      4.         ISolver developer = new Solver();
      5.         //代理:客服小姐姐
      6.         ISolver csProxy = (ISolver) new ProxyFactory(developer).getProxyInstance();
      7.         //目标方法:解决问题
      8.         csProxy.solve();
      9.     }
      10. }

    Cglib动态代理实现:

    Cglib动态代理类图

    • 目标类:Solver,这里目标类不用再实现接口。

      1. public class Solver {
      2.     public void solve() {
      3.         System.out.println("疯狂掉头发解决问题……");
      4.     }
      5. }
    • 动态代理工厂:

      1. public class ProxyFactory implements MethodInterceptor {
      2.    //维护一个目标对象
      3.     private Object target;
      4.     public ProxyFactory(Object target) {
      5.         this.target = target;
      6.     }
      7.     //为目标对象生成代理对象
      8.     public Object getProxyInstance() {
      9.         //工具类
      10.         Enhancer en = new Enhancer();
      11.         //设置父类
      12.         en.setSuperclass(target.getClass());
      13.         //设置回调函数
      14.         en.setCallback(this);
      15.         //创建子类对象代理
      16.         return en.create();
      17.     }
      18.     @Override
      19.     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
      20.         System.out.println("请问有什么可以帮到您?");
      21.         // 执行目标对象的方法
      22.         Object returnValue = method.invoke(target, args);
      23.         System.out.println("问题已经解决啦!");
      24.         return null;
      25.     }
      26. }
    • 客户端:Client

      1. public class Client {
      2.     public static void main(String[] args) {
      3.         //目标对象:程序员
      4.         Solver developer = new Solver();
      5.         //代理:客服小姐姐
      6.         Solver csProxy = (Solvernew ProxyFactory(developer).getProxyInstance();
      7.         //目标方法:解决问题
      8.         csProxy.solve();
      9.     }
      10. }

  • 相关阅读:
    计算机毕业设计Java物业信息管理系统(源码+系统+mysql数据库+Lw文档)
    ThreadPoolExecutor详解
    本来打算做功能测试的,但是发现playwright太好玩了,玩了一天,功能测试进度为空
    Azkaban (二) --------- Azkaban 入门
    Flink Catalog解读
    不想引入mq?试试debezium
    java毕业设计鑫通物流车辆调度系统mp4Mybatis+系统+数据库+调试部署
    机器学习笔记 - 使用 PyTorch 的多任务学习和 HydraNet
    再见 Typescript,你好 Javascript 原生打字 ✨
    Linux 中 Find 命令的高级用法
  • 原文地址:https://blog.csdn.net/m0_63722685/article/details/125891089