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 类和方法,可能会有较大的性能开销。
相关推荐
虾球xz几秒前
CppCon 2016 学习:The Exception Situation
开发语言·c++·学习
老土豆FUSK2 分钟前
C++ 封装特性
开发语言·c++
晨曦5432108 分钟前
学生成绩管理系统
开发语言·python
在未来等你11 分钟前
设计模式精讲 Day 4:建造者模式(Builder Pattern)
java·: design-patterns·builder-pattern·software-design·object-oriented-programming
重整旗鼓~14 分钟前
6.IK分词器拓展词库
开发语言·elasticsearch
march of Time16 分钟前
go在for循环中使用errgroup和channel进行并发处理
开发语言·golang·xcode
Cyrus_柯18 分钟前
C++(面向对象编程)
开发语言·c++·算法·面向对象
今天我要乾重生33 分钟前
java基础学习(三十)
java·开发语言·学习
Bi8bo71 小时前
Python编程基础
开发语言·python
JWASX2 小时前
【RocketMQ 生产者和消费者】- 消费者重平衡(1)
java·rocketmq·重平衡