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 类和方法,可能会有较大的性能开销。
相关推荐
2601_963869952 小时前
【计算机毕业设计】基于 Spring Boot+Vue的手工体验馆管理系统的设计与实现
java·spring boot·后端
曹牧2 小时前
Java:BeanListHandler
java·数据库·oracle
江畔柳前堤7 小时前
roLabelImg 详细安装教程
开发语言·人工智能·后端·云原生
Wang's Blog8 小时前
Go-Zero 项目开发47:自研微服务框架的必要性与核心结构设计
开发语言·微服务·golang
白鸽(二般)8 小时前
MinIO Java Client API
java·开发语言
hPw0eKIqD8 小时前
C++ 模板参数推导问题小记(非推导上下文)
开发语言·c++
临床数据科学和人工智能兴趣组9 小时前
要使用 R Markdown,首先需要安装 R 和 RStudio,接着安装 rmarkdown 包
开发语言·数据挖掘·数据分析·r语言·r语言-4.2.1
软萌萌的19 小时前
Java Spring Boot 修改yml配置&加载顺序规则
java·spring boot·python
Nebula嵌入式9 小时前
【C语言】09-深入解析main函数
linux·c语言·开发语言·嵌入式
IT小盘10 小时前
13-企业Prompt模板-角色任务约束与输出格式
java·前端·prompt