jdk动态代理和cglib动态代理对比

jdk动态代理和cglib动态代理对比:

CGLIB 和 JDK 动态代理都可以用来在运行时生成代理对象

1. 基本概念

  • JDK 动态代理 :只代理接口(interface),无法代理类。它使用 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口来实现动态代理。
  • CGLIB 动态代理:可以代理类和接口。它通过生成目标类的子类来创建代理对象,因此可以代理没有实现接口的类。

2. 使用场景

  • JDK 动态代理:适用于目标对象实现了一个或多个接口的情况。Spring AOP 默认使用 JDK 动态代理,如果目标对象没有实现接口,则使用 CGLIB。
  • CGLIB 动态代理:适用于目标对象没有实现接口或者需要代理类而不是接口的情况。

3. 性能

  • JDK 动态代理:由于使用了反射机制,性能相对较低,但对于简单接口的代理,性能差异不明显。
  • CGLIB 动态代理:通过生成字节码来创建代理对象,性能比 JDK 动态代理更高,但是生成字节码的开销较大。

4. 优缺点总结

  • JDK 动态代理

    • 优点:简单,直接使用 JDK 提供的 API,无需额外依赖。
    • 缺点:只能代理接口,性能较低。
  • CGLIB 动态代理

    • 优点:可以代理类和接口,性能较高。
    • 缺点:需要额外的 CGLIB 库,生成字节码的开销较大,无法代理 final 类和方法。

jdk动态代理:

  1. 被代理的接口和实现类:
java 复制代码
public interface Subject {
    void doSomething();
}

public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("Doing something in RealSubject");
    }
}
  1. 创建 InvocationHandler 实现类:
java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public 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("Before method execution");
        Object result = method.invoke(target, args);
        System.out.println("After method execution");
        return result;
    }
}
  1. 使用 Proxy 创建代理对象:
java 复制代码
import java.lang.reflect.Proxy;

public class JdkProxyDemo {
    public static void main(String[] args) {
        Subject realSubject = new RealSubject();
        Subject proxy = (Subject) Proxy.newProxyInstance(
            realSubject.getClass().getClassLoader(),
            realSubject.getClass().getInterfaces(),
            new MyInvocationHandler(realSubject)
        );

        proxy.doSomething();
    }
}

cglib动态代理使用步骤

CGLIB(Code Generation Library)是一个强大的高性能代码生成库,它可以在运行时动态生成字节码。CGLIB 常用于创建代理对象,特别是在 Spring 框架中,用于 AOP(面向切面编程)

  1. 添加 CGLIB 依赖项:

如果你使用的是 Maven,可以在 pom.xml 中添加以下依赖项:

XML 复制代码
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>
  1. 被代理的类
java 复制代码
public class RealSubject {
    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public void doSomething() {
        System.out.println("Doing something in RealSubject");
    }
}
  1. 创建 MethodInterceptor:
java 复制代码
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method execution");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("After method execution");
        return result;
    }
}

4.创建代理对象:

java 复制代码
import net.sf.cglib.proxy.Enhancer;

public class CglibProxyDemo {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealSubject.class);
        enhancer.setCallback(new MyMethodInterceptor());

        RealSubject proxy = (RealSubject) enhancer.create();
        proxy.doSomething();
    }
}

RealSubject 是被代理的类,MyMethodInterceptor 实现了 MethodInterceptor 接口,用于在方法执行前后添加额外的逻辑。Enhancer 类用于创建代理对象。

运行 CglibProxyDemo 类时,你会看到如下输出:

cglib jdk17 的问题:

jdk17 需要增加如下配置,否则会 报错:

--add-opens=java.base/java.lang=ALL-UNNAMED

在 JDK 9 及其之后的版本(包括 JDK 17)中,Java 引入了模块系统(Project Jigsaw),这使得访问某些内部 API 和模块变得更加严格。--add-opens 参数允许你在运行 Java 应用时开放特定的模块和包给未命名模块(通常是类路径上的代码),以便它们可以进行深层次的反射操作。

报错信息:

XML 复制代码
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @4cdf35a9
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
	at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
	at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)
	at net.sf.cglib.core.ReflectUtils$1.run(ReflectUtils.java:61)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
	at net.sf.cglib.core.ReflectUtils.<clinit>(ReflectUtils.java:52)
	at net.sf.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:243)
	at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
	at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:332)
	... 13 more
相关推荐
数据小小爬虫4 分钟前
如何利用Java爬虫获得1688商品详情
java·开发语言·爬虫
NiNg_1_2348 分钟前
IntelliJ Idea常用快捷键详解
java·ide·intellij-idea
小学鸡!10 分钟前
IDEA工具使用介绍、IDEA常用设置以及如何集成Git版本控制工具
java·git·intellij-idea
添砖,加瓦21 分钟前
java—网络编程TCP和UDP
java
晚安~~23 分钟前
考研互学互助系统|Java|SSM|VUE| 前后端分离
java·开发语言·tomcat·maven
咕德猫宁丶38 分钟前
Spring Boot + MinIO 实现分段、断点续传,让文件传输更高效
java·spring boot·后端·中间件
阿新-1 小时前
解决Spring boot集成quartz时service注入失败为null的问题
java·spring boot·后端
KaiPeng-Nie1 小时前
代码随想录day29 | leetcode 134.加油站 135.分发糖果 860.柠檬水找零 406.根据身高重建队列
java·算法·leetcode·职场和发展·贪心算法
重整旗鼓~1 小时前
8.若依系统监控与定时任务
java·spring boot
fanchael_kui1 小时前
elasticsearch-java客户端jar包中各模块的应用梳理
java·大数据·elasticsearch