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 类和方法,可能会有较大的性能开销。
相关推荐
风生u1 小时前
activiti7 详解
java
玄同7651 小时前
我的 Trae Skill 实践|使用 UV 工具一键搭建 Python 项目开发环境
开发语言·人工智能·python·langchain·uv·trae·vibe coding
岁岁种桃花儿1 小时前
SpringCloud从入门到上天:Nacos做微服务注册中心(二)
java·spring cloud·微服务
Word码1 小时前
[C++语法] 继承 (用法详解)
java·jvm·c++
Yorlen_Zhang1 小时前
Python Tkinter Text 控件完全指南:从基础编辑器到富文本应用
开发语言·python·c#
lxl13071 小时前
C++算法(1)双指针
开发语言·c++
TT哇1 小时前
【实习 】银行经理端两个核心功能的开发与修复(银行经理绑定逻辑修复和线下领取扫码功能开发)
java·vue.js
逝水如流年轻往返染尘2 小时前
Java中的数组
java
不绝1912 小时前
C#进阶:预处理指令/反射,Gettype,Typeof/关键类
开发语言·c#
无小道2 小时前
Qt-qrc机制简单介绍
开发语言·qt