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
相关推荐
customer081 小时前
【开源免费】基于SpringBoot+Vue.JS体育馆管理系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
Miketutu2 小时前
Spring MVC消息转换器
java·spring
乔冠宇2 小时前
Java手写简单Merkle树
java·区块链·merkle树
LUCIAZZZ3 小时前
简单的SQL语句的快速复习
java·数据库·sql
komo莫莫da3 小时前
寒假刷题Day19
java·开发语言
S-X-S4 小时前
算法总结-数组/字符串
java·数据结构·算法
linwq84 小时前
设计模式学习(二)
java·学习·设计模式
桦说编程5 小时前
CompletableFuture 超时功能有大坑!使用不当直接生产事故!
java·性能优化·函数式编程·并发编程
@_@哆啦A梦5 小时前
Redis 基础命令
java·数据库·redis
字节全栈_rJF6 小时前
性能测试 —— Tomcat监控与调优:status页监控_tomcat 自带监控
java·tomcat