JDK 动态代理和 Cglib 代理的区别?

JDK 动态代理和 Cglib 代理的区别?

文章目录

  • [JDK 动态代理和 Cglib 代理的区别?](#JDK 动态代理和 Cglib 代理的区别?)
    • [1. 代理机制](#1. 代理机制)
    • [2. 适用场景](#2. 适用场景)
    • [3. 生成代理的方式](#3. 生成代理的方式)
    • [4. 性能开销](#4. 性能开销)
    • [5. 兼容性](#5. 兼容性)
    • 示例代码
      • [JDK 动态代理](#JDK 动态代理)
      • [CGLIB 代理](#CGLIB 代理)
    • 总结

JDK 动态代理和 CGLIB 代理是 Java 中实现代理机制的两种常用技术,各自有不同的实现机制和适用场景。以下是它们的主要区别:

1. 代理机制

  • JDK 动态代理:

    • 基于接口:JDK 动态代理只能对实现了接口的类创建代理。它通过java.lang.reflect.Proxy类来生成代理对象。
    • 实现方式:代理对象会实现一个或多个接口,并将所有方法调用转发到 java.lang.reflect.InvocationHandler 接口的实现类中。
    • 创建方式:使用 Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 方法创建代理对象。
  • CGLIB 代理:

    • 基于类:CGLIB 代理可以代理没有实现接口的具体类。它通过继承目标类来生成代理类。
    • 实现方式:生成目标类的子类,并在子类中重写目标方法,使用 org.springframework.cglib.proxy.Enhancer 类来创建代理对象。
    • 创建方式:使用 Enhancer.setSuperclass(Class superclass) 方法设置目标类,并通过Enhancer.setCallback(MethodInterceptor callback)方法设置方法拦截器。

2. 适用场景

  • JDK 动态代理:

    • 适用接口的情况:适用于目标类实现了一个或多个接口的情况。
    • 轻量级:由于只生成实现了接口的代理对象,生成的代理类相对较轻量。
  • CGLIB 代理:

    • 适用具体类的情况:适用于目标类没有实现接口的情况,或者你需要代理具体类的情况。
    • 支持 final 类和方法:CGLIB 代理可以处理没有实现接口的类,但不能代理 final 类和 final 方法(因为 final 方法不能被重写)。

3. 生成代理的方式

  • JDK 动态代理:

    • 生成方式:在运行时生成一个实现了接口的代理类。代理类的字节码由 Java 虚拟机(JVM)动态生成。
    • 方法转发:所有方法调用都会转发到实现了InvocationHandler接口的对象中。
  • CGLIB 代理:

    • 生成方式:在运行时生成目标类的子类。子类重写目标类的方法,并通过 MethodInterceptor 处理方法调用。
    • 字节码操作:使用字节码操作库生成目标类的子类,可能涉及到复杂的字节码操作和类生成过程。

4. 性能开销

  • JDK 动态代理:

    • 性能开销:相对较小,因为只需要处理接口方法的调用。方法调用的实际逻辑在InvocationHandler中处理。
  • CGLIB 代理:

    • 性能开销:相对较大,因为需要生成目标类的子类,涉及到更多的字节码生成和继承操作。生成的代理类可能更大,内存占用更高。

5. 兼容性

  • JDK 动态代理:

    • 兼容性:不能代理 final 类和 final 方法。如果目标类或方法是 final,则无法使用 JDK 动态代理。
  • CGLIB 代理:

    • 兼容性:不能代理 final 类和 final 方法。如果目标类是 final,则 CGLIB 也不能代理。如果目标方法是 final,CGLIB 无法拦截。

示例代码

JDK 动态代理

java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkDynamicProxyDemo {
    public interface Hello {
        void sayHello();
    }

    public static class HelloImpl implements Hello {
        @Override
        public void sayHello() {
            System.out.println("你好,世界!");
        }
    }

    public static class MyInvocationHandler implements InvocationHandler {
        private final Object target;

        public MyInvocationHandler(Object target) {
            this.target = target;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("方法调用前");
            Object result = method.invoke(target, args);
            System.out.println("方法调用后");
            return result;
        }
    }

    public static void main(String[] args) {
        Hello hello = new HelloImpl();
        Hello proxy = (Hello) Proxy.newProxyInstance(
                hello.getClass().getClassLoader(),
                hello.getClass().getInterfaces(),
                new MyInvocationHandler(hello)
        );
        proxy.sayHello();
    }
}

CGLIB 代理

java 复制代码
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxyDemo {
    public static class Hello {
        public void sayHello() {
            System.out.println("你好,世界!");
        }
    }

    public static class MyMethodInterceptor implements MethodInterceptor {
        private final Object target;

        public MyMethodInterceptor(Object target) {
            this.target = target;
        }

        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("方法调用前");
            Object result = proxy.invoke(target, args);
            System.out.println("方法调用后");
            return result;
        }
    }

    public static void main(String[] args) {
        Hello hello = new Hello();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Hello.class);
        enhancer.setCallback(new MyMethodInterceptor(hello));
        Hello proxy = (Hello) enhancer.create();
        proxy.sayHello();
    }
}

总结

  • JDK 动态代理:轻量、简单,适用于接口,不能代理 final 类和方法。
  • CGLIB 代理:功能强大,适用于具体类,不能代理 final 类和方法,可能会有较大的性能开销。
相关推荐
用户1129361121925 分钟前
编译全绿,上线就崩:MyBatis 五层方法名大小写埋下的坑
java
文丑颜不良啊1 小时前
LeetCode2901~2920题目解析
java·leetcode
码云社区1 小时前
能碳管理系统开发要关注什么?能源数据、统计口径与AI分析的衔接
java·人工智能·ai·能源·能源管理系统·能碳管理系统·能碳管理系统源码
Flynn Liang1 小时前
Agentic 工作流:子代理、Supervisor 与人工介入
java·langchain·多智能体·supervisor·agentic·langchain4j
xys_6782 小时前
JavaSE通关手册:运算符
java·java-ee
starzy19902 小时前
深入理解Scala隐式值:编译期自动装配
开发语言·后端·scala
布莱克6052 小时前
Swift 条件语句详解:从 if 到 switch 的完整指南
开发语言·ssh·swift·switch·条件语句·guard·if
吴可可1232 小时前
ActiveX调用WScript.Shell原理揭秘
开发语言
jyOverQ2 小时前
从零学 JVM(七):垃圾收集器详解——Serial、ParNew、Parallel、CMS 与 G1
java·jvm
liangbo73 小时前
Spring系列11:切点表达式
java·spring